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