@firecms/user_management 3.0.0-canary.80 → 3.0.0-canary.82
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/LICENSE +3 -2
- package/dist/index.es.js +962 -774
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1539 -1
- package/dist/index.umd.js.map +1 -1
- package/package.json +5 -5
package/dist/index.es.js
CHANGED
@@ -1,319 +1,430 @@
|
|
1
|
-
import
|
2
|
-
import { getFirestore
|
3
|
-
import { jsx
|
4
|
-
import { getColorSchemeForSeed
|
5
|
-
import * as
|
6
|
-
import { toSnakeCase
|
7
|
-
import { useCreateFormex
|
8
|
-
import { format
|
9
|
-
import * as
|
10
|
-
const
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
1
|
+
import React, { useEffect, useCallback, useContext, useState } from "react";
|
2
|
+
import { getFirestore, onSnapshot, collection, setDoc, doc, addDoc, deleteDoc } from "@firebase/firestore";
|
3
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
4
|
+
import { getColorSchemeForSeed, Chip, Dialog, DialogContent, Typography, TextField, Paper, Table, TableHeader, TableCell, TableBody, TableRow, Tooltip, Checkbox, Select, SelectItem, DialogActions, Button, LoadingButton, DoneIcon, IconButton, DeleteIcon, CenteredView, Container, AddIcon, MultiSelect, MultiSelectItem } from "@firecms/ui";
|
5
|
+
import * as Yup from "yup";
|
6
|
+
import { toSnakeCase, FieldCaption, DeleteConfirmationDialog, useNavigationController, useSnackbarController, useAuthController, useCustomizationController, defaultDateFormat } from "@firecms/core";
|
7
|
+
import { useCreateFormex, getIn, Formex } from "@firecms/formex";
|
8
|
+
import { format } from "date-fns";
|
9
|
+
import * as locales from "date-fns/locale";
|
10
|
+
const RESERVED_GROUPS = ["Admin"];
|
11
|
+
const DEFAULT_PERMISSIONS = {
|
12
|
+
read: false,
|
13
|
+
edit: false,
|
14
|
+
create: false,
|
15
|
+
delete: false
|
15
16
|
};
|
16
|
-
function
|
17
|
-
collection:
|
18
|
-
user
|
17
|
+
function resolveUserRolePermissions({
|
18
|
+
collection: collection2,
|
19
|
+
user
|
19
20
|
}) {
|
20
|
-
const
|
21
|
-
if (
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
}
|
21
|
+
const roles = user?.roles;
|
22
|
+
if (!roles) {
|
23
|
+
return DEFAULT_PERMISSIONS;
|
24
|
+
} else if (collection2.ownerId === user?.uid) {
|
25
|
+
return {
|
26
|
+
read: true,
|
27
|
+
create: true,
|
28
|
+
edit: true,
|
29
|
+
delete: true
|
30
|
+
};
|
31
|
+
} else {
|
32
|
+
const basePermissions = {
|
33
|
+
read: false,
|
34
|
+
create: false,
|
35
|
+
edit: false,
|
36
|
+
delete: false
|
37
|
+
};
|
38
|
+
return roles.map((role) => resolveCollectionRole(role, collection2.id)).reduce(mergePermissions, basePermissions);
|
39
|
+
}
|
39
40
|
}
|
40
|
-
function
|
41
|
-
const
|
42
|
-
read:
|
43
|
-
create:
|
44
|
-
edit:
|
45
|
-
delete:
|
41
|
+
function resolveCollectionRole(role, id) {
|
42
|
+
const basePermissions = {
|
43
|
+
read: role.isAdmin || role.defaultPermissions?.read,
|
44
|
+
create: role.isAdmin || role.defaultPermissions?.create,
|
45
|
+
edit: role.isAdmin || role.defaultPermissions?.edit,
|
46
|
+
delete: role.isAdmin || role.defaultPermissions?.delete
|
46
47
|
};
|
47
|
-
|
48
|
+
if (role.collectionPermissions && role.collectionPermissions[id]) {
|
49
|
+
return mergePermissions(role.collectionPermissions[id], basePermissions);
|
50
|
+
} else if (role.defaultPermissions) {
|
51
|
+
return mergePermissions(role.defaultPermissions, basePermissions);
|
52
|
+
} else {
|
53
|
+
return basePermissions;
|
54
|
+
}
|
48
55
|
}
|
49
|
-
const
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
56
|
+
const mergePermissions = (permA, permB) => {
|
57
|
+
return {
|
58
|
+
read: permA.read || permB.read,
|
59
|
+
create: permA.create || permB.create,
|
60
|
+
edit: permA.edit || permB.edit,
|
61
|
+
delete: permA.delete || permB.delete
|
62
|
+
};
|
63
|
+
};
|
64
|
+
function getUserRoles(roles, fireCMSUser) {
|
65
|
+
return !roles ? void 0 : fireCMSUser.roles ? fireCMSUser.roles.map((role) => roles.find((r) => r.id === role.id)).filter(Boolean) : [];
|
57
66
|
}
|
58
|
-
const
|
59
|
-
const
|
60
|
-
|
67
|
+
const areRolesEqual = (rolesA, rolesB) => {
|
68
|
+
const rolesAIds = rolesA.map((r) => r.id);
|
69
|
+
const rolesBIds = rolesB.map((r) => r.id);
|
70
|
+
return rolesAIds.length === rolesB.length && rolesAIds.every((role) => rolesBIds.includes(role));
|
61
71
|
};
|
62
|
-
function
|
63
|
-
if (!
|
72
|
+
function cacheDelegatedLoginToken(projectId, delegatedToken) {
|
73
|
+
if (!delegatedToken) {
|
64
74
|
return;
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
75
|
+
}
|
76
|
+
const data = parseJwt(delegatedToken);
|
77
|
+
const expiry = new Date(data.exp * 1e3);
|
78
|
+
localStorage.setItem(`auth_token::${projectId}`, JSON.stringify({
|
79
|
+
token: delegatedToken,
|
80
|
+
expiry
|
69
81
|
}));
|
70
82
|
}
|
71
|
-
function
|
72
|
-
const
|
73
|
-
if (
|
74
|
-
const
|
75
|
-
|
76
|
-
|
83
|
+
function getDelegatedLoginTokenFromCache(projectId) {
|
84
|
+
const entry = localStorage.getItem(`auth_token::${projectId}`);
|
85
|
+
if (entry) {
|
86
|
+
const data = JSON.parse(entry);
|
87
|
+
data.expiry = new Date(data.expiry);
|
88
|
+
if (data.expiry > /* @__PURE__ */ new Date()) {
|
89
|
+
return data.token;
|
90
|
+
}
|
77
91
|
}
|
92
|
+
return void 0;
|
78
93
|
}
|
79
|
-
function
|
80
|
-
for (let
|
81
|
-
const
|
82
|
-
|
94
|
+
function clearDelegatedLoginTokensCache() {
|
95
|
+
for (let i = 0; i < localStorage.length; i++) {
|
96
|
+
const key = localStorage.key(i);
|
97
|
+
if (key?.startsWith("auth_token::")) {
|
98
|
+
localStorage.removeItem(key);
|
99
|
+
}
|
83
100
|
}
|
84
101
|
}
|
85
|
-
function
|
86
|
-
if (!
|
102
|
+
function parseJwt(token) {
|
103
|
+
if (!token) {
|
87
104
|
throw new Error("No JWT token");
|
88
|
-
|
89
|
-
|
105
|
+
}
|
106
|
+
const base64Url = token.split(".")[1];
|
107
|
+
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
108
|
+
const jsonPayload = decodeURIComponent(window.atob(base64).split("").map(function(c) {
|
109
|
+
return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
|
90
110
|
}).join(""));
|
91
|
-
return JSON.parse(
|
111
|
+
return JSON.parse(jsonPayload);
|
92
112
|
}
|
93
|
-
function
|
94
|
-
if (!/^#([0-9A-Fa-f]{3}){1,2}$/.test(
|
113
|
+
function darkenColor(hexColor, darkenBy = 10) {
|
114
|
+
if (!/^#([0-9A-Fa-f]{3}){1,2}$/.test(hexColor)) {
|
95
115
|
throw new Error("Invalid color format");
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
116
|
+
}
|
117
|
+
let color = hexColor.substring(1).split("");
|
118
|
+
if (color.length === 3) {
|
119
|
+
color = [color[0], color[0], color[1], color[1], color[2], color[2]];
|
120
|
+
}
|
121
|
+
let r = parseInt(color[0] + color[1], 16);
|
122
|
+
let g = parseInt(color[2] + color[3], 16);
|
123
|
+
let b = parseInt(color[4] + color[5], 16);
|
124
|
+
r = Math.floor(r * (1 - darkenBy / 100));
|
125
|
+
g = Math.floor(g * (1 - darkenBy / 100));
|
126
|
+
b = Math.floor(b * (1 - darkenBy / 100));
|
127
|
+
return "#" + (r < 16 ? "0" : "") + r.toString(16) + (g < 16 ? "0" : "") + g.toString(16) + (b < 16 ? "0" : "") + b.toString(16);
|
100
128
|
}
|
101
|
-
function
|
102
|
-
if (!/^#([0-9A-Fa-f]{3}){1,2}$/.test(
|
129
|
+
function hexToRgbaWithOpacity(hexColor, opacity = 10) {
|
130
|
+
if (!/^#([0-9A-Fa-f]{3}){1,2}$/.test(hexColor)) {
|
103
131
|
throw new Error("Invalid color format");
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
132
|
+
}
|
133
|
+
let color = hexColor.substring(1).split("");
|
134
|
+
if (color.length === 3) {
|
135
|
+
color = [color[0], color[0], color[1], color[1], color[2], color[2]];
|
136
|
+
}
|
137
|
+
const r = parseInt(color[0] + color[1], 16);
|
138
|
+
const g = parseInt(color[2] + color[3], 16);
|
139
|
+
const b = parseInt(color[4] + color[5], 16);
|
140
|
+
const alpha = opacity / 100;
|
141
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
108
142
|
}
|
109
|
-
function
|
110
|
-
firebaseApp
|
111
|
-
usersPath
|
112
|
-
rolesPath
|
113
|
-
usersLimit
|
114
|
-
canEditRoles
|
115
|
-
allowDefaultRolesCreation
|
116
|
-
includeCollectionConfigPermissions
|
143
|
+
function useFirestoreUserManagement({
|
144
|
+
firebaseApp,
|
145
|
+
usersPath = "__FIRECMS/config/users",
|
146
|
+
rolesPath = "__FIRECMS/config/roles",
|
147
|
+
usersLimit,
|
148
|
+
canEditRoles = true,
|
149
|
+
allowDefaultRolesCreation,
|
150
|
+
includeCollectionConfigPermissions
|
117
151
|
}) {
|
118
|
-
const [
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
152
|
+
const [rolesLoading, setRolesLoading] = React.useState(true);
|
153
|
+
const [usersLoading, setUsersLoading] = React.useState(true);
|
154
|
+
const [roles, setRoles] = React.useState([]);
|
155
|
+
const [usersWithRoleIds, setUsersWithRoleIds] = React.useState([]);
|
156
|
+
const users = usersWithRoleIds.map((u) => ({
|
157
|
+
...u,
|
158
|
+
roles: roles.filter((r) => u.roles?.includes(r.id))
|
159
|
+
}));
|
160
|
+
const [rolesError, setRolesError] = React.useState();
|
161
|
+
const [usersError, setUsersError] = React.useState();
|
162
|
+
const loading = rolesLoading || usersLoading;
|
163
|
+
useEffect(() => {
|
164
|
+
if (!firebaseApp || !rolesPath) return;
|
165
|
+
const firestore = getFirestore(firebaseApp);
|
166
|
+
return onSnapshot(
|
167
|
+
collection(firestore, rolesPath),
|
127
168
|
{
|
128
|
-
next: (
|
129
|
-
|
169
|
+
next: (snapshot) => {
|
170
|
+
setRolesError(void 0);
|
130
171
|
try {
|
131
|
-
const
|
132
|
-
|
133
|
-
} catch (
|
134
|
-
console.error("Error loading roles",
|
172
|
+
const newRoles = docsToRoles(snapshot.docs);
|
173
|
+
setRoles(newRoles);
|
174
|
+
} catch (e) {
|
175
|
+
console.error("Error loading roles", e);
|
176
|
+
setRolesError(e);
|
135
177
|
}
|
136
|
-
|
178
|
+
setRolesLoading(false);
|
137
179
|
},
|
138
|
-
error: (
|
139
|
-
console.error("Error loading roles",
|
180
|
+
error: (e) => {
|
181
|
+
console.error("Error loading roles", e);
|
182
|
+
setRolesError(e);
|
183
|
+
setRolesLoading(false);
|
140
184
|
}
|
141
185
|
}
|
142
186
|
);
|
143
|
-
}, [
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
187
|
+
}, [firebaseApp, rolesPath]);
|
188
|
+
useEffect(() => {
|
189
|
+
if (!firebaseApp || !usersPath) return;
|
190
|
+
const firestore = getFirestore(firebaseApp);
|
191
|
+
return onSnapshot(
|
192
|
+
collection(firestore, usersPath),
|
148
193
|
{
|
149
|
-
next: (
|
150
|
-
|
194
|
+
next: (snapshot) => {
|
195
|
+
setUsersError(void 0);
|
151
196
|
try {
|
152
|
-
const
|
153
|
-
|
154
|
-
} catch (
|
155
|
-
console.error("Error loading users",
|
197
|
+
const newUsers = docsToUsers(snapshot.docs);
|
198
|
+
setUsersWithRoleIds(newUsers);
|
199
|
+
} catch (e) {
|
200
|
+
console.error("Error loading users", e);
|
201
|
+
setUsersError(e);
|
156
202
|
}
|
157
|
-
|
203
|
+
setUsersLoading(false);
|
158
204
|
},
|
159
|
-
error: (
|
160
|
-
console.error("Error loading users",
|
205
|
+
error: (e) => {
|
206
|
+
console.error("Error loading users", e);
|
207
|
+
setUsersError(e);
|
208
|
+
setUsersLoading(false);
|
161
209
|
}
|
162
210
|
}
|
163
211
|
);
|
164
|
-
}, [
|
165
|
-
const
|
166
|
-
if (!
|
167
|
-
const
|
168
|
-
if (!
|
169
|
-
console.debug("Persisting user",
|
170
|
-
const
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
212
|
+
}, [firebaseApp, usersPath]);
|
213
|
+
const saveUser = useCallback(async (user) => {
|
214
|
+
if (!firebaseApp) throw Error("useFirestoreUserManagement Firebase not initialised");
|
215
|
+
const firestore = getFirestore(firebaseApp);
|
216
|
+
if (!firestore || !usersPath) throw Error("useFirestoreUserManagement Firestore not initialised");
|
217
|
+
console.debug("Persisting user", user);
|
218
|
+
const roleIds = user.roles?.map((r) => r.id);
|
219
|
+
const {
|
220
|
+
uid,
|
221
|
+
...userData
|
222
|
+
} = user;
|
223
|
+
const data = {
|
224
|
+
...userData,
|
225
|
+
roles: roleIds
|
176
226
|
};
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
227
|
+
if (uid) {
|
228
|
+
return setDoc(doc(firestore, usersPath, uid), data, { merge: true }).then(() => user);
|
229
|
+
} else {
|
230
|
+
return addDoc(collection(firestore, usersPath), data).then(() => user);
|
231
|
+
}
|
232
|
+
}, [usersPath, firebaseApp]);
|
233
|
+
const saveRole = useCallback((role) => {
|
234
|
+
if (!firebaseApp) throw Error("useFirestoreUserManagement Firebase not initialised");
|
235
|
+
const firestore = getFirestore(firebaseApp);
|
236
|
+
if (!firestore || !rolesPath) throw Error("useFirestoreUserManagement Firestore not initialised");
|
237
|
+
console.debug("Persisting role", role);
|
183
238
|
const {
|
184
|
-
id
|
185
|
-
...
|
186
|
-
} =
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
if (!
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
const
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
239
|
+
id,
|
240
|
+
...roleData
|
241
|
+
} = role;
|
242
|
+
const ref = doc(firestore, rolesPath, id);
|
243
|
+
return setDoc(ref, roleData, { merge: true });
|
244
|
+
}, [rolesPath, firebaseApp]);
|
245
|
+
const deleteUser = useCallback(async (user) => {
|
246
|
+
if (!firebaseApp) throw Error("useFirestoreUserManagement Firebase not initialised");
|
247
|
+
const firestore = getFirestore(firebaseApp);
|
248
|
+
if (!firestore || !usersPath) throw Error("useFirestoreUserManagement Firestore not initialised");
|
249
|
+
console.debug("Deleting", user);
|
250
|
+
const { uid } = user;
|
251
|
+
return deleteDoc(doc(firestore, usersPath, uid));
|
252
|
+
}, [usersPath, firebaseApp]);
|
253
|
+
const deleteRole = useCallback((role) => {
|
254
|
+
if (!firebaseApp) throw Error("useFirestoreUserManagement Firebase not initialised");
|
255
|
+
const firestore = getFirestore(firebaseApp);
|
256
|
+
if (!firestore || !rolesPath) throw Error("useFirestoreUserManagement Firestore not initialised");
|
257
|
+
console.debug("Deleting", role);
|
258
|
+
const { id } = role;
|
259
|
+
const ref = doc(firestore, rolesPath, id);
|
260
|
+
return deleteDoc(ref);
|
261
|
+
}, [rolesPath, firebaseApp]);
|
262
|
+
const collectionPermissions = useCallback(({
|
263
|
+
collection: collection2,
|
264
|
+
user
|
265
|
+
}) => resolveUserRolePermissions({
|
266
|
+
collection: collection2,
|
267
|
+
user
|
268
|
+
}), []);
|
269
|
+
const defineRolesFor = useCallback((user) => {
|
270
|
+
if (!users) throw Error("Users not loaded");
|
271
|
+
const mgmtUser = users.find((u) => u.email?.toLowerCase() === user?.email?.toLowerCase());
|
272
|
+
return mgmtUser?.roles;
|
273
|
+
}, [users]);
|
274
|
+
const authenticator = useCallback(({ user }) => {
|
275
|
+
console.debug("Authenticating user", user);
|
276
|
+
if (loading) {
|
277
|
+
console.warn("User management is still loading");
|
278
|
+
return false;
|
279
|
+
}
|
280
|
+
if (users.length === 0) {
|
281
|
+
return true;
|
282
|
+
}
|
283
|
+
const mgmtUser = users.find((u) => u.email?.toLowerCase() === user?.email?.toLowerCase());
|
284
|
+
if (mgmtUser) {
|
285
|
+
return true;
|
286
|
+
}
|
216
287
|
throw Error("Could not find a user with the provided email in the user management system.");
|
217
|
-
}, [
|
288
|
+
}, [loading, users]);
|
289
|
+
const isAdmin = roles.some((r) => r.id === "admin");
|
218
290
|
return {
|
219
|
-
loading
|
220
|
-
roles
|
221
|
-
users
|
222
|
-
saveUser
|
223
|
-
saveRole
|
224
|
-
rolesError
|
225
|
-
deleteUser
|
226
|
-
deleteRole
|
227
|
-
usersLimit
|
228
|
-
usersError
|
229
|
-
isAdmin
|
230
|
-
canEditRoles:
|
231
|
-
allowDefaultRolesCreation:
|
232
|
-
includeCollectionConfigPermissions:
|
233
|
-
collectionPermissions
|
234
|
-
defineRolesFor
|
235
|
-
authenticator
|
291
|
+
loading,
|
292
|
+
roles,
|
293
|
+
users,
|
294
|
+
saveUser,
|
295
|
+
saveRole,
|
296
|
+
rolesError,
|
297
|
+
deleteUser,
|
298
|
+
deleteRole,
|
299
|
+
usersLimit,
|
300
|
+
usersError,
|
301
|
+
isAdmin,
|
302
|
+
canEditRoles: canEditRoles === void 0 ? true : canEditRoles,
|
303
|
+
allowDefaultRolesCreation: allowDefaultRolesCreation === void 0 ? true : allowDefaultRolesCreation,
|
304
|
+
includeCollectionConfigPermissions: Boolean(includeCollectionConfigPermissions),
|
305
|
+
collectionPermissions,
|
306
|
+
defineRolesFor,
|
307
|
+
authenticator
|
236
308
|
};
|
237
309
|
}
|
238
|
-
const
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
}
|
247
|
-
|
248
|
-
|
249
|
-
}
|
250
|
-
|
251
|
-
|
252
|
-
|
310
|
+
const docsToUsers = (docs) => {
|
311
|
+
return docs.map((doc2) => {
|
312
|
+
const data = doc2.data();
|
313
|
+
const newVar = {
|
314
|
+
uid: doc2.id,
|
315
|
+
...data,
|
316
|
+
created_on: data?.created_on?.toDate(),
|
317
|
+
updated_on: data?.updated_on?.toDate()
|
318
|
+
};
|
319
|
+
return newVar;
|
320
|
+
});
|
321
|
+
};
|
322
|
+
const docsToRoles = (docs) => {
|
323
|
+
return docs.map((doc2) => ({
|
324
|
+
id: doc2.id,
|
325
|
+
...doc2.data()
|
326
|
+
}));
|
327
|
+
};
|
328
|
+
const UserManagementContext = React.createContext({});
|
329
|
+
function UserManagementProvider({
|
330
|
+
children,
|
331
|
+
userManagement
|
253
332
|
}) {
|
254
|
-
return /* @__PURE__ */
|
333
|
+
return /* @__PURE__ */ jsx(UserManagementContext.Provider, { value: userManagement, children });
|
255
334
|
}
|
256
|
-
const
|
257
|
-
function
|
258
|
-
let
|
259
|
-
|
260
|
-
|
335
|
+
const useUserManagement = () => useContext(UserManagementContext);
|
336
|
+
function RoleChip({ role }) {
|
337
|
+
let colorScheme;
|
338
|
+
if (role.isAdmin) {
|
339
|
+
colorScheme = "blueDarker";
|
340
|
+
} else if (role.id === "editor") {
|
341
|
+
colorScheme = "yellowLight";
|
342
|
+
} else if (role.id === "viewer") {
|
343
|
+
colorScheme = "grayLight";
|
344
|
+
} else {
|
345
|
+
colorScheme = getColorSchemeForSeed(role.id);
|
346
|
+
}
|
347
|
+
return /* @__PURE__ */ jsx(
|
348
|
+
Chip,
|
261
349
|
{
|
262
|
-
colorScheme
|
263
|
-
children:
|
350
|
+
colorScheme,
|
351
|
+
children: role.name
|
264
352
|
},
|
265
|
-
|
353
|
+
role.id
|
266
354
|
);
|
267
355
|
}
|
268
|
-
const
|
269
|
-
id:
|
270
|
-
name:
|
356
|
+
const RoleYupSchema = Yup.object().shape({
|
357
|
+
id: Yup.string().required("Required"),
|
358
|
+
name: Yup.string().required("Required")
|
271
359
|
});
|
272
|
-
function
|
273
|
-
open
|
274
|
-
role
|
275
|
-
editable
|
276
|
-
handleClose
|
277
|
-
collections
|
360
|
+
function RolesDetailsForm({
|
361
|
+
open,
|
362
|
+
role,
|
363
|
+
editable,
|
364
|
+
handleClose,
|
365
|
+
collections
|
278
366
|
}) {
|
279
|
-
const { saveRole
|
280
|
-
|
367
|
+
const { saveRole } = useUserManagement();
|
368
|
+
const isNewRole = !role;
|
369
|
+
const [savingError, setSavingError] = useState();
|
370
|
+
const onRoleUpdated = useCallback((role2) => {
|
371
|
+
setSavingError(void 0);
|
372
|
+
return saveRole(role2);
|
373
|
+
}, [saveRole]);
|
374
|
+
const formex = useCreateFormex({
|
375
|
+
initialValues: role ?? {
|
281
376
|
name: ""
|
282
377
|
},
|
283
|
-
onSubmit: (
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
})
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
378
|
+
onSubmit: (role2, formexController) => {
|
379
|
+
return onRoleUpdated(role2).then(() => {
|
380
|
+
formexController.resetForm({
|
381
|
+
values: role2
|
382
|
+
});
|
383
|
+
handleClose();
|
384
|
+
}).catch((e) => setSavingError(e));
|
385
|
+
},
|
386
|
+
validation: (values2) => {
|
387
|
+
return RoleYupSchema.validate(values2, { abortEarly: false }).then(() => ({})).catch((e) => {
|
388
|
+
const errors2 = {};
|
389
|
+
e.inner.forEach((error) => {
|
390
|
+
errors2[error.path] = error.message;
|
391
|
+
});
|
392
|
+
return errors2;
|
393
|
+
});
|
394
|
+
}
|
395
|
+
});
|
396
|
+
const {
|
397
|
+
isSubmitting,
|
398
|
+
touched,
|
399
|
+
values,
|
400
|
+
errors,
|
401
|
+
handleChange,
|
402
|
+
setFieldValue,
|
403
|
+
dirty,
|
404
|
+
setFieldTouched
|
405
|
+
} = formex;
|
406
|
+
const isAdmin = values.isAdmin ?? false;
|
407
|
+
const defaultCreate = values.defaultPermissions?.create ?? false;
|
408
|
+
const defaultRead = values.defaultPermissions?.read ?? false;
|
409
|
+
const defaultEdit = values.defaultPermissions?.edit ?? false;
|
410
|
+
const defaultDelete = values.defaultPermissions?.delete ?? false;
|
411
|
+
React.useEffect(() => {
|
412
|
+
const idTouched = getIn(touched, "id");
|
413
|
+
if (!idTouched && values.name) {
|
414
|
+
setFieldValue("id", toSnakeCase(values.name));
|
415
|
+
}
|
416
|
+
}, [touched, values.name]);
|
417
|
+
return /* @__PURE__ */ jsx(
|
418
|
+
Dialog,
|
308
419
|
{
|
309
|
-
open
|
420
|
+
open,
|
310
421
|
maxWidth: "4xl",
|
311
|
-
children: /* @__PURE__ */
|
422
|
+
children: /* @__PURE__ */ jsx(Formex, { value: formex, children: /* @__PURE__ */ jsxs(
|
312
423
|
"form",
|
313
424
|
{
|
314
|
-
noValidate:
|
425
|
+
noValidate: true,
|
315
426
|
autoComplete: "off",
|
316
|
-
onSubmit:
|
427
|
+
onSubmit: formex.handleSubmit,
|
317
428
|
style: {
|
318
429
|
display: "flex",
|
319
430
|
flexDirection: "column",
|
@@ -321,13 +432,13 @@ function Xe({
|
|
321
432
|
height: "100%"
|
322
433
|
},
|
323
434
|
children: [
|
324
|
-
/* @__PURE__ */
|
325
|
-
/* @__PURE__ */
|
435
|
+
/* @__PURE__ */ jsxs(DialogContent, { className: "flex-grow", children: [
|
436
|
+
/* @__PURE__ */ jsx(
|
326
437
|
"div",
|
327
438
|
{
|
328
439
|
className: "flex flex-row pt-12 pb-8",
|
329
|
-
children: /* @__PURE__ */
|
330
|
-
|
440
|
+
children: /* @__PURE__ */ jsx(
|
441
|
+
Typography,
|
331
442
|
{
|
332
443
|
variant: "h4",
|
333
444
|
className: "flex-grow",
|
@@ -336,161 +447,162 @@ function Xe({
|
|
336
447
|
)
|
337
448
|
}
|
338
449
|
),
|
339
|
-
/* @__PURE__ */
|
340
|
-
/* @__PURE__ */
|
341
|
-
/* @__PURE__ */
|
342
|
-
|
450
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-8", children: [
|
451
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-12 md:col-span-8", children: [
|
452
|
+
/* @__PURE__ */ jsx(
|
453
|
+
TextField,
|
343
454
|
{
|
344
455
|
name: "name",
|
345
|
-
required:
|
346
|
-
error:
|
347
|
-
value:
|
348
|
-
disabled:
|
349
|
-
onChange:
|
456
|
+
required: true,
|
457
|
+
error: touched.name && Boolean(errors.name),
|
458
|
+
value: values.name,
|
459
|
+
disabled: isAdmin || !editable,
|
460
|
+
onChange: handleChange,
|
350
461
|
"aria-describedby": "name-helper-text",
|
351
462
|
label: "Name"
|
352
463
|
}
|
353
464
|
),
|
354
|
-
/* @__PURE__ */
|
465
|
+
/* @__PURE__ */ jsx(FieldCaption, { children: touched.name && Boolean(errors.name) ? errors.name : "Name of this role" })
|
355
466
|
] }),
|
356
|
-
/* @__PURE__ */
|
357
|
-
/* @__PURE__ */
|
358
|
-
|
467
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-12 md:col-span-4", children: [
|
468
|
+
/* @__PURE__ */ jsx(
|
469
|
+
TextField,
|
359
470
|
{
|
360
471
|
name: "id",
|
361
|
-
required:
|
362
|
-
error:
|
363
|
-
value:
|
364
|
-
disabled: !
|
365
|
-
onChange: (
|
366
|
-
|
472
|
+
required: true,
|
473
|
+
error: touched.id && Boolean(errors.id),
|
474
|
+
value: values.id,
|
475
|
+
disabled: !isNewRole || !editable,
|
476
|
+
onChange: (e) => {
|
477
|
+
handleChange(e);
|
478
|
+
setFieldTouched("id", true);
|
367
479
|
},
|
368
480
|
"aria-describedby": "id-helper-text",
|
369
481
|
label: "ID"
|
370
482
|
}
|
371
483
|
),
|
372
|
-
/* @__PURE__ */
|
484
|
+
/* @__PURE__ */ jsx(FieldCaption, { children: touched.id && Boolean(errors.id) ? errors.id : "ID of this role" })
|
373
485
|
] }),
|
374
|
-
/* @__PURE__ */
|
375
|
-
/* @__PURE__ */
|
376
|
-
|
486
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-12", children: [
|
487
|
+
/* @__PURE__ */ jsx(
|
488
|
+
Paper,
|
377
489
|
{
|
378
490
|
className: "bg-inherit",
|
379
|
-
children: /* @__PURE__ */
|
380
|
-
/* @__PURE__ */
|
381
|
-
/* @__PURE__ */
|
382
|
-
/* @__PURE__ */
|
383
|
-
|
491
|
+
children: /* @__PURE__ */ jsxs(Table, { children: [
|
492
|
+
/* @__PURE__ */ jsxs(TableHeader, { children: [
|
493
|
+
/* @__PURE__ */ jsx(TableCell, {}),
|
494
|
+
/* @__PURE__ */ jsx(
|
495
|
+
TableCell,
|
384
496
|
{
|
385
497
|
align: "center",
|
386
498
|
children: "Create entities"
|
387
499
|
}
|
388
500
|
),
|
389
|
-
/* @__PURE__ */
|
390
|
-
|
501
|
+
/* @__PURE__ */ jsx(
|
502
|
+
TableCell,
|
391
503
|
{
|
392
504
|
align: "center",
|
393
505
|
children: "Read entities"
|
394
506
|
}
|
395
507
|
),
|
396
|
-
/* @__PURE__ */
|
397
|
-
|
508
|
+
/* @__PURE__ */ jsx(
|
509
|
+
TableCell,
|
398
510
|
{
|
399
511
|
align: "center",
|
400
512
|
children: "Update entities"
|
401
513
|
}
|
402
514
|
),
|
403
|
-
/* @__PURE__ */
|
404
|
-
|
515
|
+
/* @__PURE__ */ jsx(
|
516
|
+
TableCell,
|
405
517
|
{
|
406
518
|
align: "center",
|
407
519
|
children: "Delete entities"
|
408
520
|
}
|
409
521
|
)
|
410
522
|
] }),
|
411
|
-
/* @__PURE__ */
|
412
|
-
/* @__PURE__ */
|
413
|
-
/* @__PURE__ */
|
414
|
-
|
523
|
+
/* @__PURE__ */ jsxs(TableBody, { children: [
|
524
|
+
/* @__PURE__ */ jsxs(TableRow, { children: [
|
525
|
+
/* @__PURE__ */ jsx(
|
526
|
+
TableCell,
|
415
527
|
{
|
416
528
|
scope: "row",
|
417
|
-
children: /* @__PURE__ */
|
529
|
+
children: /* @__PURE__ */ jsx("strong", { children: "All collections" })
|
418
530
|
}
|
419
531
|
),
|
420
|
-
/* @__PURE__ */
|
421
|
-
|
532
|
+
/* @__PURE__ */ jsx(
|
533
|
+
TableCell,
|
422
534
|
{
|
423
535
|
align: "center",
|
424
|
-
children: /* @__PURE__ */
|
425
|
-
|
536
|
+
children: /* @__PURE__ */ jsx(
|
537
|
+
Tooltip,
|
426
538
|
{
|
427
539
|
title: "Create entities in collections",
|
428
|
-
children: /* @__PURE__ */
|
429
|
-
|
540
|
+
children: /* @__PURE__ */ jsx(
|
541
|
+
Checkbox,
|
430
542
|
{
|
431
|
-
disabled:
|
432
|
-
checked: (
|
433
|
-
onCheckedChange: (
|
543
|
+
disabled: isAdmin || !editable,
|
544
|
+
checked: (isAdmin || defaultCreate) ?? false,
|
545
|
+
onCheckedChange: (checked) => setFieldValue("defaultPermissions.create", checked)
|
434
546
|
}
|
435
547
|
)
|
436
548
|
}
|
437
549
|
)
|
438
550
|
}
|
439
551
|
),
|
440
|
-
/* @__PURE__ */
|
441
|
-
|
552
|
+
/* @__PURE__ */ jsx(
|
553
|
+
TableCell,
|
442
554
|
{
|
443
555
|
align: "center",
|
444
|
-
children: /* @__PURE__ */
|
445
|
-
|
556
|
+
children: /* @__PURE__ */ jsx(
|
557
|
+
Tooltip,
|
446
558
|
{
|
447
559
|
title: "Access all data in every collection",
|
448
|
-
children: /* @__PURE__ */
|
449
|
-
|
560
|
+
children: /* @__PURE__ */ jsx(
|
561
|
+
Checkbox,
|
450
562
|
{
|
451
|
-
disabled:
|
452
|
-
checked: (
|
453
|
-
onCheckedChange: (
|
563
|
+
disabled: isAdmin || !editable,
|
564
|
+
checked: (isAdmin || defaultRead) ?? false,
|
565
|
+
onCheckedChange: (checked) => setFieldValue("defaultPermissions.read", checked)
|
454
566
|
}
|
455
567
|
)
|
456
568
|
}
|
457
569
|
)
|
458
570
|
}
|
459
571
|
),
|
460
|
-
/* @__PURE__ */
|
461
|
-
|
572
|
+
/* @__PURE__ */ jsx(
|
573
|
+
TableCell,
|
462
574
|
{
|
463
575
|
align: "center",
|
464
|
-
children: /* @__PURE__ */
|
465
|
-
|
576
|
+
children: /* @__PURE__ */ jsx(
|
577
|
+
Tooltip,
|
466
578
|
{
|
467
579
|
title: "Update data in any collection",
|
468
|
-
children: /* @__PURE__ */
|
469
|
-
|
580
|
+
children: /* @__PURE__ */ jsx(
|
581
|
+
Checkbox,
|
470
582
|
{
|
471
|
-
disabled:
|
472
|
-
checked: (
|
473
|
-
onCheckedChange: (
|
583
|
+
disabled: isAdmin || !editable,
|
584
|
+
checked: (isAdmin || defaultEdit) ?? false,
|
585
|
+
onCheckedChange: (checked) => setFieldValue("defaultPermissions.edit", checked)
|
474
586
|
}
|
475
587
|
)
|
476
588
|
}
|
477
589
|
)
|
478
590
|
}
|
479
591
|
),
|
480
|
-
/* @__PURE__ */
|
481
|
-
|
592
|
+
/* @__PURE__ */ jsx(
|
593
|
+
TableCell,
|
482
594
|
{
|
483
595
|
align: "center",
|
484
|
-
children: /* @__PURE__ */
|
485
|
-
|
596
|
+
children: /* @__PURE__ */ jsx(
|
597
|
+
Tooltip,
|
486
598
|
{
|
487
599
|
title: "Delete data in any collection",
|
488
|
-
children: /* @__PURE__ */
|
489
|
-
|
600
|
+
children: /* @__PURE__ */ jsx(
|
601
|
+
Checkbox,
|
490
602
|
{
|
491
|
-
disabled:
|
492
|
-
checked: (
|
493
|
-
onCheckedChange: (
|
603
|
+
disabled: isAdmin || !editable,
|
604
|
+
checked: (isAdmin || defaultDelete) ?? false,
|
605
|
+
onCheckedChange: (checked) => setFieldValue("defaultPermissions.delete", checked)
|
494
606
|
}
|
495
607
|
)
|
496
608
|
}
|
@@ -498,100 +610,100 @@ function Xe({
|
|
498
610
|
}
|
499
611
|
)
|
500
612
|
] }),
|
501
|
-
|
502
|
-
/* @__PURE__ */
|
503
|
-
|
613
|
+
collections && collections.map((col) => /* @__PURE__ */ jsxs(TableRow, { children: [
|
614
|
+
/* @__PURE__ */ jsx(
|
615
|
+
TableCell,
|
504
616
|
{
|
505
617
|
scope: "row",
|
506
|
-
children:
|
618
|
+
children: col.name
|
507
619
|
}
|
508
620
|
),
|
509
|
-
/* @__PURE__ */
|
510
|
-
|
621
|
+
/* @__PURE__ */ jsx(
|
622
|
+
TableCell,
|
511
623
|
{
|
512
624
|
align: "center",
|
513
|
-
children: /* @__PURE__ */
|
514
|
-
|
625
|
+
children: /* @__PURE__ */ jsx(
|
626
|
+
Checkbox,
|
515
627
|
{
|
516
|
-
disabled:
|
517
|
-
checked: (
|
518
|
-
onCheckedChange: (
|
628
|
+
disabled: isAdmin || defaultCreate || !editable,
|
629
|
+
checked: (isAdmin || defaultCreate || getIn(values, `collectionPermissions.${col.path}.create`)) ?? false,
|
630
|
+
onCheckedChange: (checked) => setFieldValue(`collectionPermissions.${col.path}.create`, checked)
|
519
631
|
}
|
520
632
|
)
|
521
633
|
}
|
522
634
|
),
|
523
|
-
/* @__PURE__ */
|
524
|
-
|
635
|
+
/* @__PURE__ */ jsx(
|
636
|
+
TableCell,
|
525
637
|
{
|
526
638
|
align: "center",
|
527
|
-
children: /* @__PURE__ */
|
528
|
-
|
639
|
+
children: /* @__PURE__ */ jsx(
|
640
|
+
Checkbox,
|
529
641
|
{
|
530
|
-
disabled:
|
531
|
-
checked: (
|
532
|
-
onCheckedChange: (
|
642
|
+
disabled: isAdmin || defaultRead || !editable,
|
643
|
+
checked: (isAdmin || defaultRead || getIn(values, `collectionPermissions.${col.path}.read`)) ?? false,
|
644
|
+
onCheckedChange: (checked) => setFieldValue(`collectionPermissions.${col.path}.read`, checked)
|
533
645
|
}
|
534
646
|
)
|
535
647
|
}
|
536
648
|
),
|
537
|
-
/* @__PURE__ */
|
538
|
-
|
649
|
+
/* @__PURE__ */ jsx(
|
650
|
+
TableCell,
|
539
651
|
{
|
540
652
|
align: "center",
|
541
|
-
children: /* @__PURE__ */
|
542
|
-
|
653
|
+
children: /* @__PURE__ */ jsx(
|
654
|
+
Checkbox,
|
543
655
|
{
|
544
|
-
disabled:
|
545
|
-
checked: (
|
546
|
-
onCheckedChange: (
|
656
|
+
disabled: isAdmin || defaultEdit || !editable,
|
657
|
+
checked: (isAdmin || defaultEdit || getIn(values, `collectionPermissions.${col.path}.edit`)) ?? false,
|
658
|
+
onCheckedChange: (checked) => setFieldValue(`collectionPermissions.${col.path}.edit`, checked)
|
547
659
|
}
|
548
660
|
)
|
549
661
|
}
|
550
662
|
),
|
551
|
-
/* @__PURE__ */
|
552
|
-
|
663
|
+
/* @__PURE__ */ jsx(
|
664
|
+
TableCell,
|
553
665
|
{
|
554
666
|
align: "center",
|
555
|
-
children: /* @__PURE__ */
|
556
|
-
|
667
|
+
children: /* @__PURE__ */ jsx(
|
668
|
+
Checkbox,
|
557
669
|
{
|
558
|
-
disabled:
|
559
|
-
checked: (
|
560
|
-
onCheckedChange: (
|
670
|
+
disabled: isAdmin || defaultDelete || !editable,
|
671
|
+
checked: (isAdmin || defaultDelete || getIn(values, `collectionPermissions.${col.path}.delete`)) ?? false,
|
672
|
+
onCheckedChange: (checked) => setFieldValue(`collectionPermissions.${col.path}.delete`, checked)
|
561
673
|
}
|
562
674
|
)
|
563
675
|
}
|
564
676
|
)
|
565
|
-
] },
|
677
|
+
] }, col.name))
|
566
678
|
] })
|
567
679
|
] })
|
568
680
|
}
|
569
681
|
),
|
570
|
-
/* @__PURE__ */
|
682
|
+
/* @__PURE__ */ jsx(FieldCaption, { children: "You can customise the permissions that the users related to this role can perform in the entities of each collection" })
|
571
683
|
] }),
|
572
|
-
/* @__PURE__ */
|
573
|
-
/* @__PURE__ */
|
574
|
-
|
684
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-12 md:col-span-4", children: [
|
685
|
+
/* @__PURE__ */ jsxs(
|
686
|
+
Select,
|
575
687
|
{
|
576
|
-
error:
|
688
|
+
error: touched.config && Boolean(errors.config),
|
577
689
|
id: "createCollections",
|
578
690
|
name: "createCollections",
|
579
691
|
label: "Create collections",
|
580
692
|
position: "item-aligned",
|
581
|
-
disabled:
|
582
|
-
onChange: (
|
583
|
-
value:
|
584
|
-
renderValue: (
|
693
|
+
disabled: isAdmin || !editable,
|
694
|
+
onChange: (event) => setFieldValue("config.createCollections", event.target.value === "true"),
|
695
|
+
value: isAdmin || values.config?.createCollections ? "true" : "false",
|
696
|
+
renderValue: (value) => value === "true" ? "Yes" : "No",
|
585
697
|
children: [
|
586
|
-
/* @__PURE__ */
|
587
|
-
|
698
|
+
/* @__PURE__ */ jsx(
|
699
|
+
SelectItem,
|
588
700
|
{
|
589
701
|
value: "true",
|
590
702
|
children: " Yes "
|
591
703
|
}
|
592
704
|
),
|
593
|
-
/* @__PURE__ */
|
594
|
-
|
705
|
+
/* @__PURE__ */ jsx(
|
706
|
+
SelectItem,
|
595
707
|
{
|
596
708
|
value: "false",
|
597
709
|
children: " No "
|
@@ -600,38 +712,38 @@ function Xe({
|
|
600
712
|
]
|
601
713
|
}
|
602
714
|
),
|
603
|
-
/* @__PURE__ */
|
715
|
+
/* @__PURE__ */ jsx(FieldCaption, { children: touched.config && Boolean(errors.config) ? errors.config : "Can the user create collections" })
|
604
716
|
] }),
|
605
|
-
/* @__PURE__ */
|
606
|
-
/* @__PURE__ */
|
607
|
-
|
717
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-12 md:col-span-4", children: [
|
718
|
+
/* @__PURE__ */ jsxs(
|
719
|
+
Select,
|
608
720
|
{
|
609
|
-
error:
|
721
|
+
error: touched.config && Boolean(errors.config),
|
610
722
|
id: "editCollections",
|
611
723
|
name: "editCollections",
|
612
724
|
label: "Edit collections",
|
613
|
-
disabled:
|
725
|
+
disabled: isAdmin || !editable,
|
614
726
|
position: "item-aligned",
|
615
|
-
onChange: (
|
616
|
-
value:
|
617
|
-
renderValue: (
|
727
|
+
onChange: (event) => setFieldValue("config.editCollections", event.target.value === "own" ? "own" : event.target.value === "true"),
|
728
|
+
value: isAdmin ? "true" : values.config?.editCollections === "own" ? "own" : values.config?.editCollections ? "true" : "false",
|
729
|
+
renderValue: (value) => value === "own" ? "Own" : value === "true" ? "Yes" : "No",
|
618
730
|
children: [
|
619
|
-
/* @__PURE__ */
|
620
|
-
|
731
|
+
/* @__PURE__ */ jsx(
|
732
|
+
SelectItem,
|
621
733
|
{
|
622
734
|
value: "true",
|
623
735
|
children: " Yes "
|
624
736
|
}
|
625
737
|
),
|
626
|
-
/* @__PURE__ */
|
627
|
-
|
738
|
+
/* @__PURE__ */ jsx(
|
739
|
+
SelectItem,
|
628
740
|
{
|
629
741
|
value: "false",
|
630
742
|
children: " No "
|
631
743
|
}
|
632
744
|
),
|
633
|
-
/* @__PURE__ */
|
634
|
-
|
745
|
+
/* @__PURE__ */ jsx(
|
746
|
+
SelectItem,
|
635
747
|
{
|
636
748
|
value: "own",
|
637
749
|
children: " Only his/her own "
|
@@ -640,38 +752,38 @@ function Xe({
|
|
640
752
|
]
|
641
753
|
}
|
642
754
|
),
|
643
|
-
/* @__PURE__ */
|
755
|
+
/* @__PURE__ */ jsx(FieldCaption, { children: touched.config && Boolean(errors.config) ? errors.config : "Can the user edit collections" })
|
644
756
|
] }),
|
645
|
-
/* @__PURE__ */
|
646
|
-
/* @__PURE__ */
|
647
|
-
|
757
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-12 md:col-span-4", children: [
|
758
|
+
/* @__PURE__ */ jsxs(
|
759
|
+
Select,
|
648
760
|
{
|
649
|
-
error:
|
761
|
+
error: touched.config && Boolean(errors.config),
|
650
762
|
id: "deleteCollections",
|
651
763
|
name: "deleteCollections",
|
652
764
|
label: "Delete collections",
|
653
|
-
disabled:
|
765
|
+
disabled: isAdmin || !editable,
|
654
766
|
position: "item-aligned",
|
655
|
-
onChange: (
|
656
|
-
value:
|
657
|
-
renderValue: (
|
767
|
+
onChange: (event) => setFieldValue("config.deleteCollections", event.target.value === "own" ? "own" : event.target.value === "true"),
|
768
|
+
value: isAdmin ? "true" : values.config?.deleteCollections === "own" ? "own" : values.config?.deleteCollections ? "true" : "false",
|
769
|
+
renderValue: (value) => value === "own" ? "Own" : value === "true" ? "Yes" : "No",
|
658
770
|
children: [
|
659
|
-
/* @__PURE__ */
|
660
|
-
|
771
|
+
/* @__PURE__ */ jsx(
|
772
|
+
SelectItem,
|
661
773
|
{
|
662
774
|
value: "true",
|
663
775
|
children: " Yes "
|
664
776
|
}
|
665
777
|
),
|
666
|
-
/* @__PURE__ */
|
667
|
-
|
778
|
+
/* @__PURE__ */ jsx(
|
779
|
+
SelectItem,
|
668
780
|
{
|
669
781
|
value: "false",
|
670
782
|
children: " No "
|
671
783
|
}
|
672
784
|
),
|
673
|
-
/* @__PURE__ */
|
674
|
-
|
785
|
+
/* @__PURE__ */ jsx(
|
786
|
+
SelectItem,
|
675
787
|
{
|
676
788
|
value: "own",
|
677
789
|
children: " Only his/her own "
|
@@ -680,32 +792,32 @@ function Xe({
|
|
680
792
|
]
|
681
793
|
}
|
682
794
|
),
|
683
|
-
/* @__PURE__ */
|
795
|
+
/* @__PURE__ */ jsx(FieldCaption, { children: touched.config && Boolean(errors.config) ? errors.config : "Can the user delete collections" })
|
684
796
|
] })
|
685
797
|
] })
|
686
798
|
] }),
|
687
|
-
/* @__PURE__ */
|
688
|
-
|
689
|
-
/* @__PURE__ */
|
690
|
-
|
799
|
+
/* @__PURE__ */ jsxs(DialogActions, { position: "sticky", children: [
|
800
|
+
savingError && /* @__PURE__ */ jsx(Typography, { className: "text-red-500", children: "There was an error saving this role" }),
|
801
|
+
/* @__PURE__ */ jsx(
|
802
|
+
Button,
|
691
803
|
{
|
692
804
|
variant: "text",
|
693
805
|
onClick: () => {
|
694
|
-
|
806
|
+
handleClose();
|
695
807
|
},
|
696
808
|
children: "Cancel"
|
697
809
|
}
|
698
810
|
),
|
699
|
-
/* @__PURE__ */
|
700
|
-
|
811
|
+
/* @__PURE__ */ jsx(
|
812
|
+
LoadingButton,
|
701
813
|
{
|
702
814
|
variant: "filled",
|
703
815
|
color: "primary",
|
704
816
|
type: "submit",
|
705
|
-
disabled: !
|
706
|
-
loading:
|
707
|
-
startIcon: /* @__PURE__ */
|
708
|
-
children:
|
817
|
+
disabled: !dirty,
|
818
|
+
loading: isSubmitting,
|
819
|
+
startIcon: /* @__PURE__ */ jsx(DoneIcon, {}),
|
820
|
+
children: isNewRole ? "Create role" : "Update"
|
709
821
|
}
|
710
822
|
)
|
711
823
|
] })
|
@@ -715,24 +827,24 @@ function Xe({
|
|
715
827
|
}
|
716
828
|
);
|
717
829
|
}
|
718
|
-
const
|
830
|
+
const DEFAULT_ROLES = [
|
719
831
|
{
|
720
832
|
id: "admin",
|
721
833
|
name: "Admin",
|
722
|
-
isAdmin:
|
834
|
+
isAdmin: true
|
723
835
|
},
|
724
836
|
{
|
725
837
|
id: "editor",
|
726
838
|
name: "Editor",
|
727
|
-
isAdmin:
|
839
|
+
isAdmin: false,
|
728
840
|
defaultPermissions: {
|
729
|
-
read:
|
730
|
-
create:
|
731
|
-
edit:
|
732
|
-
delete:
|
841
|
+
read: true,
|
842
|
+
create: true,
|
843
|
+
edit: true,
|
844
|
+
delete: true
|
733
845
|
},
|
734
846
|
config: {
|
735
|
-
createCollections:
|
847
|
+
createCollections: true,
|
736
848
|
editCollections: "own",
|
737
849
|
deleteCollections: "own"
|
738
850
|
}
|
@@ -740,78 +852,86 @@ const Se = [
|
|
740
852
|
{
|
741
853
|
id: "viewer",
|
742
854
|
name: "Viewer",
|
743
|
-
isAdmin:
|
855
|
+
isAdmin: false,
|
744
856
|
defaultPermissions: {
|
745
|
-
read:
|
746
|
-
create:
|
747
|
-
edit:
|
748
|
-
delete:
|
857
|
+
read: true,
|
858
|
+
create: false,
|
859
|
+
edit: false,
|
860
|
+
delete: false
|
749
861
|
}
|
750
862
|
}
|
751
863
|
];
|
752
|
-
function
|
753
|
-
onRoleClicked
|
754
|
-
editable
|
864
|
+
function RolesTable({
|
865
|
+
onRoleClicked,
|
866
|
+
editable
|
755
867
|
}) {
|
756
868
|
const {
|
757
|
-
roles
|
758
|
-
saveRole
|
759
|
-
deleteRole
|
760
|
-
allowDefaultRolesCreation
|
761
|
-
} =
|
762
|
-
|
869
|
+
roles,
|
870
|
+
saveRole,
|
871
|
+
deleteRole,
|
872
|
+
allowDefaultRolesCreation
|
873
|
+
} = useUserManagement();
|
874
|
+
const [roleToBeDeleted, setRoleToBeDeleted] = useState(void 0);
|
875
|
+
const [deleteInProgress, setDeleteInProgress] = useState(false);
|
876
|
+
return /* @__PURE__ */ jsxs(
|
763
877
|
"div",
|
764
878
|
{
|
765
879
|
className: "w-full overflow-auto",
|
766
880
|
children: [
|
767
|
-
/* @__PURE__ */
|
768
|
-
/* @__PURE__ */
|
769
|
-
/* @__PURE__ */
|
770
|
-
/* @__PURE__ */
|
771
|
-
/* @__PURE__ */
|
772
|
-
/* @__PURE__ */
|
881
|
+
/* @__PURE__ */ jsxs(Table, { children: [
|
882
|
+
/* @__PURE__ */ jsxs(TableHeader, { children: [
|
883
|
+
/* @__PURE__ */ jsx(TableCell, { header: true, className: "w-16" }),
|
884
|
+
/* @__PURE__ */ jsx(TableCell, { header: true, children: "Role" }),
|
885
|
+
/* @__PURE__ */ jsx(TableCell, { header: true, className: "items-center", children: "Is Admin" }),
|
886
|
+
/* @__PURE__ */ jsx(TableCell, { header: true, children: "Default permissions" })
|
773
887
|
] }),
|
774
|
-
/* @__PURE__ */
|
775
|
-
|
776
|
-
const
|
777
|
-
|
778
|
-
|
888
|
+
/* @__PURE__ */ jsxs(TableBody, { children: [
|
889
|
+
roles && roles.map((role) => {
|
890
|
+
const canCreateAll = role.isAdmin || role.defaultPermissions?.create;
|
891
|
+
const canReadAll = role.isAdmin || role.defaultPermissions?.read;
|
892
|
+
const canUpdateAll = role.isAdmin || role.defaultPermissions?.edit;
|
893
|
+
const canDeleteAll = role.isAdmin || role.defaultPermissions?.delete;
|
894
|
+
return /* @__PURE__ */ jsxs(
|
895
|
+
TableRow,
|
779
896
|
{
|
780
897
|
onClick: () => {
|
781
|
-
|
898
|
+
onRoleClicked(role);
|
782
899
|
},
|
783
900
|
children: [
|
784
|
-
/* @__PURE__ */
|
785
|
-
|
901
|
+
/* @__PURE__ */ jsx(TableCell, { style: { width: "64px" }, children: !role.isAdmin && /* @__PURE__ */ jsx(Tooltip, { title: "Delete this role", children: /* @__PURE__ */ jsx(
|
902
|
+
IconButton,
|
786
903
|
{
|
787
904
|
size: "small",
|
788
|
-
disabled: !
|
789
|
-
onClick: (
|
790
|
-
|
905
|
+
disabled: !editable,
|
906
|
+
onClick: (event) => {
|
907
|
+
event.stopPropagation();
|
908
|
+
return setRoleToBeDeleted(role);
|
909
|
+
},
|
910
|
+
children: /* @__PURE__ */ jsx(DeleteIcon, {})
|
791
911
|
}
|
792
912
|
) }) }),
|
793
|
-
/* @__PURE__ */
|
794
|
-
/* @__PURE__ */
|
795
|
-
/* @__PURE__ */
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
913
|
+
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(RoleChip, { role }) }),
|
914
|
+
/* @__PURE__ */ jsx(TableCell, { className: "items-center", children: /* @__PURE__ */ jsx(Checkbox, { checked: role.isAdmin ?? false }) }),
|
915
|
+
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsxs("ul", { children: [
|
916
|
+
canCreateAll && /* @__PURE__ */ jsx("li", { children: "Create" }),
|
917
|
+
canReadAll && /* @__PURE__ */ jsx("li", { children: "Read" }),
|
918
|
+
canUpdateAll && /* @__PURE__ */ jsx("li", { children: "Update" }),
|
919
|
+
canDeleteAll && /* @__PURE__ */ jsx("li", { children: "Delete" })
|
800
920
|
] }) })
|
801
921
|
]
|
802
922
|
},
|
803
|
-
|
923
|
+
role.name
|
804
924
|
);
|
805
925
|
}),
|
806
|
-
(!
|
807
|
-
/* @__PURE__ */
|
808
|
-
|
809
|
-
|
926
|
+
(!roles || roles.length === 0) && /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colspan: 4, children: /* @__PURE__ */ jsxs(CenteredView, { className: "flex flex-col gap-4 my-8 items-center", children: [
|
927
|
+
/* @__PURE__ */ jsx(Typography, { variant: "label", children: "You don't have any roles yet." }),
|
928
|
+
allowDefaultRolesCreation && /* @__PURE__ */ jsx(
|
929
|
+
Button,
|
810
930
|
{
|
811
931
|
variant: "outlined",
|
812
932
|
onClick: () => {
|
813
|
-
|
814
|
-
|
933
|
+
DEFAULT_ROLES.forEach((role) => {
|
934
|
+
saveRole(role);
|
815
935
|
});
|
816
936
|
},
|
817
937
|
children: "Create default roles"
|
@@ -820,146 +940,182 @@ function Ze({
|
|
820
940
|
] }) }) })
|
821
941
|
] })
|
822
942
|
] }),
|
823
|
-
/* @__PURE__ */
|
824
|
-
|
943
|
+
/* @__PURE__ */ jsx(
|
944
|
+
DeleteConfirmationDialog,
|
825
945
|
{
|
826
|
-
open:
|
827
|
-
loading:
|
946
|
+
open: Boolean(roleToBeDeleted),
|
947
|
+
loading: deleteInProgress,
|
828
948
|
onAccept: () => {
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
949
|
+
if (roleToBeDeleted) {
|
950
|
+
setDeleteInProgress(true);
|
951
|
+
deleteRole(roleToBeDeleted).then(() => {
|
952
|
+
setRoleToBeDeleted(void 0);
|
953
|
+
}).finally(() => {
|
954
|
+
setDeleteInProgress(false);
|
955
|
+
});
|
956
|
+
}
|
834
957
|
},
|
835
958
|
onCancel: () => {
|
836
|
-
|
959
|
+
setRoleToBeDeleted(void 0);
|
837
960
|
},
|
838
|
-
title: /* @__PURE__ */
|
839
|
-
body: /* @__PURE__ */
|
961
|
+
title: /* @__PURE__ */ jsx(Fragment, { children: "Delete?" }),
|
962
|
+
body: /* @__PURE__ */ jsx(Fragment, { children: "Are you sure you want to delete this role?" })
|
840
963
|
}
|
841
964
|
)
|
842
965
|
]
|
843
966
|
}
|
844
967
|
);
|
845
968
|
}
|
846
|
-
const
|
847
|
-
function({ children
|
848
|
-
const { collections
|
849
|
-
|
969
|
+
const RolesView = React.memo(
|
970
|
+
function RolesView2({ children }) {
|
971
|
+
const { collections } = useNavigationController();
|
972
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
973
|
+
const [selectedRole, setSelectedRole] = useState();
|
974
|
+
const { canEditRoles } = useUserManagement();
|
975
|
+
const onRoleClicked = useCallback((user) => {
|
976
|
+
setDialogOpen(true);
|
977
|
+
setSelectedRole(user);
|
850
978
|
}, []);
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
979
|
+
const handleClose = () => {
|
980
|
+
setSelectedRole(void 0);
|
981
|
+
setDialogOpen(false);
|
982
|
+
};
|
983
|
+
return /* @__PURE__ */ jsxs(Container, { className: "w-full flex flex-col py-4 gap-4", maxWidth: "6xl", children: [
|
984
|
+
children,
|
985
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center mt-12", children: [
|
986
|
+
/* @__PURE__ */ jsx(
|
987
|
+
Typography,
|
856
988
|
{
|
857
|
-
gutterBottom:
|
989
|
+
gutterBottom: true,
|
858
990
|
variant: "h4",
|
859
991
|
className: "flex-grow",
|
860
992
|
component: "h4",
|
861
993
|
children: "Roles"
|
862
994
|
}
|
863
995
|
),
|
864
|
-
/* @__PURE__ */
|
865
|
-
|
996
|
+
/* @__PURE__ */ jsx(Tooltip, { title: !canEditRoles ? "Update plans to customise roles" : void 0, children: /* @__PURE__ */ jsx(
|
997
|
+
Button,
|
866
998
|
{
|
867
999
|
size: "large",
|
868
|
-
disabled: !
|
869
|
-
startIcon: /* @__PURE__ */
|
870
|
-
onClick: () =>
|
1000
|
+
disabled: !canEditRoles,
|
1001
|
+
startIcon: /* @__PURE__ */ jsx(AddIcon, {}),
|
1002
|
+
onClick: () => setDialogOpen(true),
|
871
1003
|
children: "Add role"
|
872
1004
|
}
|
873
1005
|
) })
|
874
1006
|
] }),
|
875
|
-
/* @__PURE__ */
|
876
|
-
/* @__PURE__ */
|
877
|
-
|
1007
|
+
/* @__PURE__ */ jsx(RolesTable, { onRoleClicked, editable: Boolean(canEditRoles) }),
|
1008
|
+
/* @__PURE__ */ jsx(
|
1009
|
+
RolesDetailsForm,
|
878
1010
|
{
|
879
|
-
open:
|
880
|
-
role:
|
881
|
-
editable:
|
882
|
-
collections
|
883
|
-
handleClose
|
884
|
-
g(void 0), i(!1);
|
885
|
-
}
|
1011
|
+
open: dialogOpen,
|
1012
|
+
role: selectedRole,
|
1013
|
+
editable: canEditRoles,
|
1014
|
+
collections,
|
1015
|
+
handleClose
|
886
1016
|
},
|
887
|
-
|
1017
|
+
selectedRole?.id ?? "new"
|
888
1018
|
)
|
889
1019
|
] });
|
890
1020
|
}
|
891
|
-
)
|
892
|
-
|
893
|
-
|
894
|
-
|
1021
|
+
);
|
1022
|
+
const UserYupSchema = Yup.object().shape({
|
1023
|
+
displayName: Yup.string().required("Required"),
|
1024
|
+
email: Yup.string().email().required("Required"),
|
1025
|
+
roles: Yup.array().min(1)
|
895
1026
|
});
|
896
|
-
function
|
897
|
-
const
|
898
|
-
|
1027
|
+
function canUserBeEdited(loggedUser, user, users, roles, prevUser) {
|
1028
|
+
const admins = users.filter((u) => u.roles?.map((r) => r.id).includes("admin"));
|
1029
|
+
const loggedUserIsAdmin = loggedUser.roles?.map((r) => r.id).includes("admin");
|
1030
|
+
const didRolesChange = !prevUser || !areRolesEqual(prevUser.roles ?? [], user.roles ?? []);
|
1031
|
+
if (didRolesChange && !loggedUserIsAdmin) {
|
899
1032
|
throw new Error("Only admins can change roles");
|
900
|
-
|
1033
|
+
}
|
1034
|
+
const adminRoleRemoved = prevUser && prevUser.roles?.map((r) => r.id).includes("admin") && !user.roles?.map((r) => r.id).includes("admin");
|
1035
|
+
if (adminRoleRemoved && admins.length === 1) {
|
901
1036
|
throw new Error("There must be at least one admin");
|
902
|
-
|
1037
|
+
}
|
1038
|
+
return true;
|
903
1039
|
}
|
904
|
-
function
|
905
|
-
open
|
906
|
-
user:
|
907
|
-
handleClose
|
1040
|
+
function UserDetailsForm({
|
1041
|
+
open,
|
1042
|
+
user: userProp,
|
1043
|
+
handleClose
|
908
1044
|
}) {
|
909
|
-
const
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
1045
|
+
const snackbarController = useSnackbarController();
|
1046
|
+
const {
|
1047
|
+
user: loggedInUser
|
1048
|
+
} = useAuthController();
|
1049
|
+
const {
|
1050
|
+
saveUser,
|
1051
|
+
users,
|
1052
|
+
roles
|
1053
|
+
} = useUserManagement();
|
1054
|
+
const isNewUser = !userProp;
|
1055
|
+
const onUserUpdated = useCallback((savedUser) => {
|
1056
|
+
if (!loggedInUser) {
|
917
1057
|
throw new Error("Logged user not found");
|
1058
|
+
}
|
918
1059
|
try {
|
919
|
-
|
920
|
-
|
921
|
-
|
1060
|
+
canUserBeEdited(loggedInUser, savedUser, users, roles, userProp);
|
1061
|
+
return saveUser(savedUser);
|
1062
|
+
} catch (e) {
|
1063
|
+
return Promise.reject(e);
|
922
1064
|
}
|
923
|
-
}, [
|
924
|
-
|
1065
|
+
}, [roles, saveUser, userProp, users, loggedInUser]);
|
1066
|
+
const formex = useCreateFormex({
|
1067
|
+
initialValues: userProp ?? {
|
925
1068
|
displayName: "",
|
926
1069
|
email: "",
|
927
|
-
roles:
|
1070
|
+
roles: roles.filter((r) => r.id === "editor")
|
928
1071
|
},
|
929
|
-
validation: (
|
930
|
-
|
931
|
-
|
932
|
-
|
1072
|
+
validation: (values2) => {
|
1073
|
+
return UserYupSchema.validate(values2, { abortEarly: false }).then(() => {
|
1074
|
+
return {};
|
1075
|
+
}).catch((e) => {
|
1076
|
+
return e.inner.reduce((acc, error) => {
|
1077
|
+
acc[error.path] = error.message;
|
1078
|
+
return acc;
|
1079
|
+
}, {});
|
933
1080
|
});
|
934
|
-
}
|
935
|
-
|
936
|
-
|
937
|
-
|
1081
|
+
},
|
1082
|
+
onSubmit: (user, formexController) => {
|
1083
|
+
return onUserUpdated(user).then(() => {
|
1084
|
+
handleClose();
|
1085
|
+
formexController.resetForm({
|
1086
|
+
values: user
|
1087
|
+
});
|
1088
|
+
}).catch((e) => {
|
1089
|
+
snackbarController.open({
|
1090
|
+
type: "error",
|
1091
|
+
message: e.message
|
1092
|
+
});
|
938
1093
|
});
|
939
|
-
}
|
940
|
-
})
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
1094
|
+
}
|
1095
|
+
});
|
1096
|
+
const {
|
1097
|
+
isSubmitting,
|
1098
|
+
touched,
|
1099
|
+
handleChange,
|
1100
|
+
values,
|
1101
|
+
errors,
|
1102
|
+
setFieldValue,
|
1103
|
+
dirty,
|
1104
|
+
handleSubmit,
|
1105
|
+
submitCount
|
1106
|
+
} = formex;
|
1107
|
+
return /* @__PURE__ */ jsx(
|
1108
|
+
Dialog,
|
953
1109
|
{
|
954
|
-
open
|
955
|
-
onOpenChange: (
|
1110
|
+
open,
|
1111
|
+
onOpenChange: (open2) => !open2 ? handleClose() : void 0,
|
956
1112
|
maxWidth: "4xl",
|
957
|
-
children: /* @__PURE__ */
|
1113
|
+
children: /* @__PURE__ */ jsx(Formex, { value: formex, children: /* @__PURE__ */ jsxs(
|
958
1114
|
"form",
|
959
1115
|
{
|
960
|
-
onSubmit:
|
1116
|
+
onSubmit: handleSubmit,
|
961
1117
|
autoComplete: "off",
|
962
|
-
noValidate:
|
1118
|
+
noValidate: true,
|
963
1119
|
style: {
|
964
1120
|
display: "flex",
|
965
1121
|
flexDirection: "column",
|
@@ -967,13 +1123,13 @@ function rn({
|
|
967
1123
|
height: "100%"
|
968
1124
|
},
|
969
1125
|
children: [
|
970
|
-
/* @__PURE__ */
|
971
|
-
/* @__PURE__ */
|
1126
|
+
/* @__PURE__ */ jsxs(DialogContent, { className: "h-full flex-grow", children: [
|
1127
|
+
/* @__PURE__ */ jsx(
|
972
1128
|
"div",
|
973
1129
|
{
|
974
1130
|
className: "flex flex-row pt-4 pb-4",
|
975
|
-
children: /* @__PURE__ */
|
976
|
-
|
1131
|
+
children: /* @__PURE__ */ jsx(
|
1132
|
+
Typography,
|
977
1133
|
{
|
978
1134
|
variant: "h4",
|
979
1135
|
className: "flex-grow",
|
@@ -982,80 +1138,81 @@ function rn({
|
|
982
1138
|
)
|
983
1139
|
}
|
984
1140
|
),
|
985
|
-
/* @__PURE__ */
|
986
|
-
/* @__PURE__ */
|
987
|
-
/* @__PURE__ */
|
988
|
-
|
1141
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-8", children: [
|
1142
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-12", children: [
|
1143
|
+
/* @__PURE__ */ jsx(
|
1144
|
+
TextField,
|
989
1145
|
{
|
990
1146
|
name: "displayName",
|
991
|
-
required:
|
992
|
-
error:
|
993
|
-
value:
|
994
|
-
onChange:
|
1147
|
+
required: true,
|
1148
|
+
error: submitCount > 0 && Boolean(errors.displayName),
|
1149
|
+
value: values.displayName ?? "",
|
1150
|
+
onChange: handleChange,
|
995
1151
|
"aria-describedby": "name-helper-text",
|
996
1152
|
label: "Name"
|
997
1153
|
}
|
998
1154
|
),
|
999
|
-
/* @__PURE__ */
|
1155
|
+
/* @__PURE__ */ jsx(FieldCaption, { children: submitCount > 0 && Boolean(errors.displayName) ? errors.displayName : "Name of this user" })
|
1000
1156
|
] }),
|
1001
|
-
/* @__PURE__ */
|
1002
|
-
/* @__PURE__ */
|
1003
|
-
|
1157
|
+
/* @__PURE__ */ jsxs("div", { className: "col-span-12", children: [
|
1158
|
+
/* @__PURE__ */ jsx(
|
1159
|
+
TextField,
|
1004
1160
|
{
|
1005
|
-
required:
|
1006
|
-
error:
|
1161
|
+
required: true,
|
1162
|
+
error: submitCount > 0 && Boolean(errors.email),
|
1007
1163
|
name: "email",
|
1008
|
-
value:
|
1009
|
-
onChange:
|
1164
|
+
value: values.email ?? "",
|
1165
|
+
onChange: handleChange,
|
1010
1166
|
"aria-describedby": "email-helper-text",
|
1011
1167
|
label: "Email"
|
1012
1168
|
}
|
1013
1169
|
),
|
1014
|
-
/* @__PURE__ */
|
1170
|
+
/* @__PURE__ */ jsx(FieldCaption, { children: submitCount > 0 && Boolean(errors.email) ? errors.email : "Email of this user" })
|
1015
1171
|
] }),
|
1016
|
-
/* @__PURE__ */
|
1017
|
-
|
1172
|
+
/* @__PURE__ */ jsx("div", { className: "col-span-12", children: /* @__PURE__ */ jsx(
|
1173
|
+
MultiSelect,
|
1018
1174
|
{
|
1019
1175
|
label: "Roles",
|
1020
|
-
value:
|
1021
|
-
onMultiValueChange: (
|
1022
|
-
renderValue: (
|
1023
|
-
const
|
1024
|
-
|
1176
|
+
value: values.roles?.map((r) => r.id) ?? [],
|
1177
|
+
onMultiValueChange: (value) => setFieldValue("roles", value.map((id) => roles.find((r) => r.id === id))),
|
1178
|
+
renderValue: (value) => {
|
1179
|
+
const userRole = roles.find((role) => role.id === value);
|
1180
|
+
if (!userRole) return null;
|
1181
|
+
return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap space-x-2 space-y-2", children: /* @__PURE__ */ jsx(RoleChip, { role: userRole }, userRole?.id) });
|
1025
1182
|
},
|
1026
|
-
children:
|
1027
|
-
|
1183
|
+
children: roles.map((userRole) => /* @__PURE__ */ jsx(
|
1184
|
+
MultiSelectItem,
|
1028
1185
|
{
|
1029
|
-
value:
|
1030
|
-
children: /* @__PURE__ */
|
1186
|
+
value: userRole.id,
|
1187
|
+
children: /* @__PURE__ */ jsx(RoleChip, { role: userRole }, userRole?.id)
|
1031
1188
|
},
|
1032
|
-
|
1189
|
+
userRole.id
|
1033
1190
|
))
|
1034
1191
|
}
|
1035
1192
|
) })
|
1036
1193
|
] })
|
1037
1194
|
] }),
|
1038
|
-
/* @__PURE__ */
|
1039
|
-
/* @__PURE__ */
|
1040
|
-
|
1195
|
+
/* @__PURE__ */ jsxs(DialogActions, { children: [
|
1196
|
+
/* @__PURE__ */ jsx(
|
1197
|
+
Button,
|
1041
1198
|
{
|
1042
1199
|
variant: "text",
|
1043
1200
|
onClick: () => {
|
1044
|
-
|
1201
|
+
handleClose();
|
1045
1202
|
},
|
1046
1203
|
children: "Cancel"
|
1047
1204
|
}
|
1048
1205
|
),
|
1049
|
-
/* @__PURE__ */
|
1050
|
-
|
1206
|
+
/* @__PURE__ */ jsx(
|
1207
|
+
LoadingButton,
|
1051
1208
|
{
|
1052
1209
|
variant: "filled",
|
1053
1210
|
color: "primary",
|
1054
1211
|
type: "submit",
|
1055
|
-
disabled: !
|
1056
|
-
loading:
|
1057
|
-
startIcon: /* @__PURE__ */
|
1058
|
-
children:
|
1212
|
+
disabled: !dirty,
|
1213
|
+
loading: isSubmitting,
|
1214
|
+
startIcon: /* @__PURE__ */ jsx(DoneIcon, {}),
|
1215
|
+
children: isNewUser ? "Create user" : "Update"
|
1059
1216
|
}
|
1060
1217
|
)
|
1061
1218
|
] })
|
@@ -1065,79 +1222,91 @@ function rn({
|
|
1065
1222
|
}
|
1066
1223
|
);
|
1067
1224
|
}
|
1068
|
-
function
|
1225
|
+
function UsersTable({ onUserClicked }) {
|
1069
1226
|
const {
|
1070
|
-
users
|
1071
|
-
saveUser
|
1072
|
-
deleteUser
|
1073
|
-
} =
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1227
|
+
users,
|
1228
|
+
saveUser,
|
1229
|
+
deleteUser
|
1230
|
+
} = useUserManagement();
|
1231
|
+
const authController = useAuthController();
|
1232
|
+
const snackbarController = useSnackbarController();
|
1233
|
+
const customizationController = useCustomizationController();
|
1234
|
+
const dateUtilsLocale = customizationController?.locale ? locales[customizationController?.locale] : void 0;
|
1235
|
+
const dateFormat = customizationController?.dateTimeFormat ?? defaultDateFormat;
|
1236
|
+
const [userToBeDeleted, setUserToBeDeleted] = useState(void 0);
|
1237
|
+
const [deleteInProgress, setDeleteInProgress] = useState(false);
|
1238
|
+
return /* @__PURE__ */ jsxs("div", { className: "overflow-auto", children: [
|
1239
|
+
/* @__PURE__ */ jsxs(Table, { children: [
|
1240
|
+
/* @__PURE__ */ jsxs(TableHeader, { children: [
|
1241
|
+
/* @__PURE__ */ jsx(TableCell, { className: "truncate w-16" }),
|
1242
|
+
/* @__PURE__ */ jsx(TableCell, { children: "ID" }),
|
1243
|
+
/* @__PURE__ */ jsx(TableCell, { children: "Email" }),
|
1244
|
+
/* @__PURE__ */ jsx(TableCell, { children: "Name" }),
|
1245
|
+
/* @__PURE__ */ jsx(TableCell, { children: "Roles" }),
|
1246
|
+
/* @__PURE__ */ jsx(TableCell, { children: "Created on" })
|
1083
1247
|
] }),
|
1084
|
-
/* @__PURE__ */
|
1085
|
-
|
1086
|
-
const
|
1087
|
-
|
1088
|
-
|
1248
|
+
/* @__PURE__ */ jsxs(TableBody, { children: [
|
1249
|
+
users && users.map((user) => {
|
1250
|
+
const userRoles = user.roles;
|
1251
|
+
const formattedDate = user.created_on ? format(user.created_on, dateFormat, { locale: dateUtilsLocale }) : "";
|
1252
|
+
return /* @__PURE__ */ jsxs(
|
1253
|
+
TableRow,
|
1089
1254
|
{
|
1090
1255
|
onClick: () => {
|
1091
|
-
|
1256
|
+
onUserClicked(user);
|
1092
1257
|
},
|
1093
1258
|
children: [
|
1094
|
-
/* @__PURE__ */
|
1095
|
-
|
1259
|
+
/* @__PURE__ */ jsx(TableCell, { className: "w-10", children: /* @__PURE__ */ jsx(Tooltip, { title: "Delete this user", children: /* @__PURE__ */ jsx(
|
1260
|
+
IconButton,
|
1096
1261
|
{
|
1097
1262
|
size: "small",
|
1098
|
-
onClick: (
|
1099
|
-
|
1263
|
+
onClick: (event) => {
|
1264
|
+
event.stopPropagation();
|
1265
|
+
return setUserToBeDeleted(user);
|
1266
|
+
},
|
1267
|
+
children: /* @__PURE__ */ jsx(DeleteIcon, {})
|
1100
1268
|
}
|
1101
1269
|
) }) }),
|
1102
|
-
/* @__PURE__ */
|
1103
|
-
/* @__PURE__ */
|
1104
|
-
/* @__PURE__ */
|
1105
|
-
/* @__PURE__ */
|
1106
|
-
(
|
1270
|
+
/* @__PURE__ */ jsx(TableCell, { children: user.uid }),
|
1271
|
+
/* @__PURE__ */ jsx(TableCell, { children: user.email }),
|
1272
|
+
/* @__PURE__ */ jsx(TableCell, { className: "font-medium align-left", children: user.displayName }),
|
1273
|
+
/* @__PURE__ */ jsx(TableCell, { className: "align-left", children: userRoles ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: userRoles.map(
|
1274
|
+
(userRole) => /* @__PURE__ */ jsx(RoleChip, { role: userRole }, userRole?.id)
|
1107
1275
|
) }) : null }),
|
1108
|
-
/* @__PURE__ */
|
1276
|
+
/* @__PURE__ */ jsx(TableCell, { children: formattedDate })
|
1109
1277
|
]
|
1110
1278
|
},
|
1111
|
-
"row_" +
|
1279
|
+
"row_" + user.uid
|
1112
1280
|
);
|
1113
1281
|
}),
|
1114
|
-
(!
|
1115
|
-
/* @__PURE__ */
|
1116
|
-
/* @__PURE__ */
|
1117
|
-
|
1282
|
+
(!users || users.length === 0) && /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colspan: 6, children: /* @__PURE__ */ jsxs(CenteredView, { className: "flex flex-col gap-4 my-8 items-center", children: [
|
1283
|
+
/* @__PURE__ */ jsx(Typography, { variant: "label", children: "There are no users yet" }),
|
1284
|
+
/* @__PURE__ */ jsx(
|
1285
|
+
Button,
|
1118
1286
|
{
|
1119
1287
|
variant: "outlined",
|
1120
1288
|
onClick: () => {
|
1121
|
-
if (!
|
1289
|
+
if (!authController.user?.uid) {
|
1122
1290
|
throw Error("UsersTable, authController misconfiguration");
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1291
|
+
}
|
1292
|
+
saveUser({
|
1293
|
+
uid: authController.user?.uid,
|
1294
|
+
email: authController.user?.email,
|
1295
|
+
displayName: authController.user?.displayName,
|
1296
|
+
photoURL: authController.user?.photoURL,
|
1297
|
+
providerId: authController.user?.providerId,
|
1298
|
+
isAnonymous: authController.user?.isAnonymous,
|
1130
1299
|
roles: [{ id: "admin", name: "Admin" }],
|
1131
1300
|
created_on: /* @__PURE__ */ new Date()
|
1132
1301
|
}).then(() => {
|
1133
|
-
|
1302
|
+
snackbarController.open({
|
1134
1303
|
type: "success",
|
1135
1304
|
message: "User added successfully"
|
1136
1305
|
});
|
1137
|
-
}).catch((
|
1138
|
-
|
1306
|
+
}).catch((error) => {
|
1307
|
+
snackbarController.open({
|
1139
1308
|
type: "error",
|
1140
|
-
message: "Error adding user: " +
|
1309
|
+
message: "Error adding user: " + error.message
|
1141
1310
|
});
|
1142
1311
|
});
|
1143
1312
|
},
|
@@ -1147,193 +1316,212 @@ function on({ onUserClicked: t }) {
|
|
1147
1316
|
] }) }) })
|
1148
1317
|
] })
|
1149
1318
|
] }),
|
1150
|
-
/* @__PURE__ */
|
1151
|
-
|
1319
|
+
/* @__PURE__ */ jsx(
|
1320
|
+
DeleteConfirmationDialog,
|
1152
1321
|
{
|
1153
|
-
open:
|
1154
|
-
loading:
|
1322
|
+
open: Boolean(userToBeDeleted),
|
1323
|
+
loading: deleteInProgress,
|
1155
1324
|
onAccept: () => {
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1325
|
+
if (userToBeDeleted) {
|
1326
|
+
setDeleteInProgress(true);
|
1327
|
+
deleteUser(userToBeDeleted).then(() => {
|
1328
|
+
setUserToBeDeleted(void 0);
|
1329
|
+
}).catch((error) => {
|
1330
|
+
snackbarController.open({
|
1331
|
+
type: "error",
|
1332
|
+
message: "Error deleting user: " + error.message
|
1333
|
+
});
|
1334
|
+
}).finally(() => {
|
1335
|
+
setDeleteInProgress(false);
|
1162
1336
|
});
|
1163
|
-
}
|
1164
|
-
U(!1);
|
1165
|
-
}));
|
1337
|
+
}
|
1166
1338
|
},
|
1167
1339
|
onCancel: () => {
|
1168
|
-
|
1340
|
+
setUserToBeDeleted(void 0);
|
1169
1341
|
},
|
1170
|
-
title: /* @__PURE__ */
|
1171
|
-
body: /* @__PURE__ */
|
1342
|
+
title: /* @__PURE__ */ jsx(Fragment, { children: "Delete?" }),
|
1343
|
+
body: /* @__PURE__ */ jsx(Fragment, { children: "Are you sure you want to delete this user?" })
|
1172
1344
|
}
|
1173
1345
|
)
|
1174
1346
|
] });
|
1175
1347
|
}
|
1176
|
-
const
|
1177
|
-
const [
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1348
|
+
const UsersView = function UsersView2({ children }) {
|
1349
|
+
const [dialogOpen, setDialogOpen] = useState();
|
1350
|
+
const [selectedUser, setSelectedUser] = useState();
|
1351
|
+
const { users, usersLimit } = useUserManagement();
|
1352
|
+
const reachedUsersLimit = usersLimit !== void 0 && (users && users.length >= usersLimit);
|
1353
|
+
const onUserClicked = useCallback((user) => {
|
1354
|
+
setSelectedUser(user);
|
1355
|
+
setDialogOpen(true);
|
1356
|
+
}, []);
|
1357
|
+
const handleClose = useCallback(() => {
|
1358
|
+
setDialogOpen(false);
|
1359
|
+
setSelectedUser(void 0);
|
1181
1360
|
}, []);
|
1182
|
-
return /* @__PURE__ */
|
1183
|
-
|
1184
|
-
/* @__PURE__ */
|
1361
|
+
return /* @__PURE__ */ jsxs(Container, { className: "w-full flex flex-col py-4 gap-4", maxWidth: "6xl", children: [
|
1362
|
+
children,
|
1363
|
+
/* @__PURE__ */ jsxs(
|
1185
1364
|
"div",
|
1186
1365
|
{
|
1187
1366
|
className: "flex items-center mt-12",
|
1188
1367
|
children: [
|
1189
|
-
/* @__PURE__ */
|
1190
|
-
|
1368
|
+
/* @__PURE__ */ jsx(
|
1369
|
+
Typography,
|
1191
1370
|
{
|
1192
|
-
gutterBottom:
|
1371
|
+
gutterBottom: true,
|
1193
1372
|
variant: "h4",
|
1194
1373
|
className: "flex-grow",
|
1195
1374
|
component: "h4",
|
1196
1375
|
children: "Users"
|
1197
1376
|
}
|
1198
1377
|
),
|
1199
|
-
/* @__PURE__ */
|
1200
|
-
|
1378
|
+
/* @__PURE__ */ jsx(
|
1379
|
+
Button,
|
1201
1380
|
{
|
1202
1381
|
size: "large",
|
1203
|
-
disabled:
|
1204
|
-
startIcon: /* @__PURE__ */
|
1205
|
-
onClick: () =>
|
1382
|
+
disabled: reachedUsersLimit,
|
1383
|
+
startIcon: /* @__PURE__ */ jsx(AddIcon, {}),
|
1384
|
+
onClick: () => setDialogOpen(true),
|
1206
1385
|
children: "Add user"
|
1207
1386
|
}
|
1208
1387
|
)
|
1209
1388
|
]
|
1210
1389
|
}
|
1211
1390
|
),
|
1212
|
-
/* @__PURE__ */
|
1213
|
-
/* @__PURE__ */
|
1214
|
-
|
1391
|
+
/* @__PURE__ */ jsx(UsersTable, { onUserClicked }),
|
1392
|
+
/* @__PURE__ */ jsx(
|
1393
|
+
UserDetailsForm,
|
1215
1394
|
{
|
1216
|
-
open:
|
1217
|
-
user:
|
1218
|
-
handleClose
|
1395
|
+
open: dialogOpen ?? false,
|
1396
|
+
user: selectedUser,
|
1397
|
+
handleClose
|
1219
1398
|
},
|
1220
|
-
|
1399
|
+
selectedUser?.uid ?? "new"
|
1221
1400
|
)
|
1222
1401
|
] });
|
1223
1402
|
};
|
1224
|
-
function
|
1225
|
-
const
|
1403
|
+
function useUserManagementPlugin({ userManagement }) {
|
1404
|
+
const noUsers = userManagement.users.length === 0;
|
1405
|
+
const noRoles = userManagement.roles.length === 0;
|
1226
1406
|
return {
|
1227
1407
|
key: "user_management",
|
1228
|
-
loading:
|
1408
|
+
loading: userManagement.loading,
|
1229
1409
|
homePage: {
|
1230
|
-
additionalChildrenStart:
|
1231
|
-
|
1410
|
+
additionalChildrenStart: noUsers || noRoles ? /* @__PURE__ */ jsx(
|
1411
|
+
IntroWidget,
|
1232
1412
|
{
|
1233
|
-
noUsers
|
1234
|
-
noRoles
|
1235
|
-
userManagement
|
1413
|
+
noUsers,
|
1414
|
+
noRoles,
|
1415
|
+
userManagement
|
1236
1416
|
}
|
1237
1417
|
) : void 0
|
1238
1418
|
},
|
1239
1419
|
provider: {
|
1240
|
-
Component:
|
1420
|
+
Component: UserManagementProvider,
|
1241
1421
|
props: {
|
1242
|
-
userManagement
|
1422
|
+
userManagement
|
1243
1423
|
}
|
1244
1424
|
}
|
1245
1425
|
};
|
1246
1426
|
}
|
1247
|
-
function
|
1248
|
-
noUsers
|
1249
|
-
noRoles
|
1250
|
-
userManagement
|
1427
|
+
function IntroWidget({
|
1428
|
+
noUsers,
|
1429
|
+
noRoles,
|
1430
|
+
userManagement
|
1251
1431
|
}) {
|
1252
|
-
const
|
1253
|
-
|
1254
|
-
|
1432
|
+
const authController = useAuthController();
|
1433
|
+
const snackbarController = useSnackbarController();
|
1434
|
+
const buttonLabel = noUsers && noRoles ? "Create default roles and add current user as admin" : noUsers ? "Add current user as admin" : noRoles ? "Create default roles" : void 0;
|
1435
|
+
return /* @__PURE__ */ jsxs(
|
1436
|
+
Paper,
|
1255
1437
|
{
|
1256
1438
|
className: "my-4 flex flex-col px-4 py-6 bg-white dark:bg-slate-800 gap-2",
|
1257
1439
|
children: [
|
1258
|
-
/* @__PURE__ */
|
1259
|
-
/* @__PURE__ */
|
1260
|
-
/* @__PURE__ */
|
1261
|
-
if (!
|
1440
|
+
/* @__PURE__ */ jsx(Typography, { variant: "subtitle2", className: "uppercase", children: "Create your users and roles" }),
|
1441
|
+
/* @__PURE__ */ jsx(Typography, { children: "You have no users or roles defined. You can create default roles and add the current user as admin." }),
|
1442
|
+
/* @__PURE__ */ jsxs(Button, { onClick: () => {
|
1443
|
+
if (!authController.user?.uid) {
|
1262
1444
|
throw Error("UsersTable, authController misconfiguration");
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1445
|
+
}
|
1446
|
+
if (noUsers) {
|
1447
|
+
userManagement.saveUser({
|
1448
|
+
uid: authController.user?.uid,
|
1449
|
+
email: authController.user?.email,
|
1450
|
+
displayName: authController.user?.displayName,
|
1451
|
+
photoURL: authController.user?.photoURL,
|
1452
|
+
providerId: authController.user?.providerId,
|
1453
|
+
isAnonymous: authController.user?.isAnonymous,
|
1454
|
+
roles: [{
|
1455
|
+
id: "admin",
|
1456
|
+
name: "Admin"
|
1457
|
+
}],
|
1458
|
+
created_on: /* @__PURE__ */ new Date()
|
1459
|
+
}).then(() => {
|
1460
|
+
snackbarController.open({
|
1461
|
+
type: "success",
|
1462
|
+
message: "User added successfully"
|
1463
|
+
});
|
1464
|
+
}).catch((error) => {
|
1465
|
+
snackbarController.open({
|
1466
|
+
type: "error",
|
1467
|
+
message: "Error adding user: " + error.message
|
1468
|
+
});
|
1279
1469
|
});
|
1280
|
-
}
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1470
|
+
}
|
1471
|
+
if (noRoles) {
|
1472
|
+
DEFAULT_ROLES.forEach((role) => {
|
1473
|
+
userManagement.saveRole(role);
|
1284
1474
|
});
|
1285
|
-
}
|
1286
|
-
n.saveRole(g);
|
1287
|
-
});
|
1475
|
+
}
|
1288
1476
|
}, children: [
|
1289
|
-
/* @__PURE__ */
|
1290
|
-
|
1477
|
+
/* @__PURE__ */ jsx(AddIcon, {}),
|
1478
|
+
buttonLabel
|
1291
1479
|
] })
|
1292
1480
|
]
|
1293
1481
|
}
|
1294
1482
|
);
|
1295
1483
|
}
|
1296
|
-
const
|
1484
|
+
const userManagementAdminViews = [
|
1297
1485
|
{
|
1298
1486
|
path: "users",
|
1299
1487
|
name: "CMS Users",
|
1300
1488
|
group: "Admin",
|
1301
1489
|
icon: "face",
|
1302
|
-
view: /* @__PURE__ */
|
1490
|
+
view: /* @__PURE__ */ jsx(UsersView, {})
|
1303
1491
|
},
|
1304
1492
|
{
|
1305
1493
|
path: "roles",
|
1306
1494
|
name: "Roles",
|
1307
1495
|
group: "Admin",
|
1308
1496
|
icon: "gpp_good",
|
1309
|
-
view: /* @__PURE__ */
|
1497
|
+
view: /* @__PURE__ */ jsx(RolesView, {})
|
1310
1498
|
}
|
1311
1499
|
];
|
1312
1500
|
export {
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1501
|
+
IntroWidget,
|
1502
|
+
RESERVED_GROUPS,
|
1503
|
+
RoleChip,
|
1504
|
+
RoleYupSchema,
|
1505
|
+
RolesDetailsForm,
|
1506
|
+
RolesTable,
|
1507
|
+
RolesView,
|
1508
|
+
UserDetailsForm,
|
1509
|
+
UserManagementContext,
|
1510
|
+
UserManagementProvider,
|
1511
|
+
UserYupSchema,
|
1512
|
+
UsersTable,
|
1513
|
+
UsersView,
|
1514
|
+
areRolesEqual,
|
1515
|
+
cacheDelegatedLoginToken,
|
1516
|
+
clearDelegatedLoginTokensCache,
|
1517
|
+
darkenColor,
|
1518
|
+
getDelegatedLoginTokenFromCache,
|
1519
|
+
getUserRoles,
|
1520
|
+
hexToRgbaWithOpacity,
|
1521
|
+
resolveUserRolePermissions,
|
1522
|
+
useFirestoreUserManagement,
|
1523
|
+
useUserManagement,
|
1524
|
+
useUserManagementPlugin,
|
1525
|
+
userManagementAdminViews
|
1338
1526
|
};
|
1339
1527
|
//# sourceMappingURL=index.es.js.map
|