@firecms/user_management 3.0.0-canary.117 → 3.0.0-canary.119
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/dist/index.es.js +50 -16
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +51 -17
- package/dist/index.umd.js.map +1 -1
- package/package.json +5 -5
- package/src/components/roles/RolesDetailsForm.tsx +32 -11
- package/src/hooks/useBuildUserManagement.tsx +33 -8
- package/src/utils/permissions.ts +3 -2
package/dist/index.es.js
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
import React, { useEffect, useCallback, useContext, useState } from "react";
|
2
2
|
import equal from "react-fast-compare";
|
3
|
+
import { removeUndefined, useAuthController, toSnakeCase, FieldCaption, DeleteConfirmationDialog, useNavigationController, useSnackbarController, useCustomizationController, defaultDateFormat } from "@firecms/core";
|
3
4
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
4
5
|
import { getColorSchemeForSeed, Chip, Dialog, DialogContent, Typography, TextField, Paper, Table, TableHeader, TableCell, TableBody, TableRow, Tooltip, Checkbox, Button, Select, SelectItem, DialogActions, LoadingButton, DoneIcon, IconButton, DeleteIcon, CenteredView, Container, AddIcon, MultiSelect, MultiSelectItem } from "@firecms/ui";
|
5
6
|
import * as Yup from "yup";
|
6
|
-
import { toSnakeCase, FieldCaption, DeleteConfirmationDialog, useNavigationController, useSnackbarController, useAuthController, useCustomizationController, defaultDateFormat } from "@firecms/core";
|
7
7
|
import { useCreateFormex, getIn, Formex } from "@firecms/formex";
|
8
8
|
import { format } from "date-fns";
|
9
9
|
import * as locales from "date-fns/locale";
|
@@ -45,8 +45,9 @@ function resolveCollectionRole(role, id) {
|
|
45
45
|
edit: role.isAdmin || role.defaultPermissions?.edit,
|
46
46
|
delete: role.isAdmin || role.defaultPermissions?.delete
|
47
47
|
};
|
48
|
-
|
49
|
-
|
48
|
+
const thisCollectionPermissions = role.collectionPermissions?.[id];
|
49
|
+
if (thisCollectionPermissions) {
|
50
|
+
return mergePermissions(thisCollectionPermissions, basePermissions);
|
50
51
|
} else if (role.defaultPermissions) {
|
51
52
|
return mergePermissions(role.defaultPermissions, basePermissions);
|
52
53
|
} else {
|
@@ -163,6 +164,11 @@ function useBuildUserManagement({
|
|
163
164
|
useEffect(() => {
|
164
165
|
if (!dataSourceDelegate || !rolesPath) return;
|
165
166
|
if (dataSourceDelegate.initialised !== void 0 && !dataSourceDelegate.initialised) return;
|
167
|
+
if (dataSourceDelegate.authenticated !== void 0 && !dataSourceDelegate.authenticated) {
|
168
|
+
setRolesLoading(false);
|
169
|
+
return;
|
170
|
+
}
|
171
|
+
setRolesLoading(true);
|
166
172
|
return dataSourceDelegate.listenCollection?.({
|
167
173
|
path: rolesPath,
|
168
174
|
onUpdate(entities) {
|
@@ -185,10 +191,15 @@ function useBuildUserManagement({
|
|
185
191
|
setRolesLoading(false);
|
186
192
|
}
|
187
193
|
});
|
188
|
-
}, [dataSourceDelegate?.initialised, rolesPath]);
|
194
|
+
}, [dataSourceDelegate?.initialised, dataSourceDelegate?.authenticated, rolesPath]);
|
189
195
|
useEffect(() => {
|
190
196
|
if (!dataSourceDelegate || !usersPath) return;
|
191
197
|
if (dataSourceDelegate.initialised !== void 0 && !dataSourceDelegate.initialised) return;
|
198
|
+
if (dataSourceDelegate.authenticated !== void 0 && !dataSourceDelegate.authenticated) {
|
199
|
+
setUsersLoading(false);
|
200
|
+
return;
|
201
|
+
}
|
202
|
+
setUsersLoading(true);
|
192
203
|
return dataSourceDelegate.listenCollection?.({
|
193
204
|
path: usersPath,
|
194
205
|
onUpdate(entities) {
|
@@ -211,7 +222,7 @@ function useBuildUserManagement({
|
|
211
222
|
setUsersLoading(false);
|
212
223
|
}
|
213
224
|
});
|
214
|
-
}, [dataSourceDelegate?.initialised, usersPath]);
|
225
|
+
}, [dataSourceDelegate?.initialised, dataSourceDelegate?.authenticated, usersPath]);
|
215
226
|
const saveUser = useCallback(async (user) => {
|
216
227
|
if (!dataSourceDelegate) throw Error("useBuildUserManagement Firebase not initialised");
|
217
228
|
if (!usersPath) throw Error("useBuildUserManagement Firestore not initialised");
|
@@ -219,15 +230,19 @@ function useBuildUserManagement({
|
|
219
230
|
const roleIds = user.roles?.map((r) => r.id);
|
220
231
|
const email = user.email?.toLowerCase().trim();
|
221
232
|
if (!email) throw Error("Email is required");
|
233
|
+
const userExists = users.find((u) => u.email?.toLowerCase() === email);
|
222
234
|
const data = {
|
223
235
|
...user,
|
224
|
-
roles: roleIds
|
236
|
+
roles: roleIds ?? []
|
225
237
|
};
|
238
|
+
if (!userExists) {
|
239
|
+
data.created_on = /* @__PURE__ */ new Date();
|
240
|
+
}
|
226
241
|
return dataSourceDelegate.saveEntity({
|
227
242
|
status: "existing",
|
228
243
|
path: usersPath,
|
229
244
|
entityId: email,
|
230
|
-
values: data
|
245
|
+
values: removeUndefined(data)
|
231
246
|
}).then(() => user);
|
232
247
|
}, [usersPath, dataSourceDelegate?.initialised]);
|
233
248
|
const saveRole = useCallback((role) => {
|
@@ -242,7 +257,7 @@ function useBuildUserManagement({
|
|
242
257
|
status: "existing",
|
243
258
|
path: rolesPath,
|
244
259
|
entityId: id,
|
245
|
-
values: roleData
|
260
|
+
values: removeUndefined(roleData)
|
246
261
|
}).then(() => {
|
247
262
|
return;
|
248
263
|
});
|
@@ -297,7 +312,7 @@ function useBuildUserManagement({
|
|
297
312
|
return true;
|
298
313
|
}
|
299
314
|
throw Error("Could not find a user with the provided email in the user management system.");
|
300
|
-
}, [loading, users]);
|
315
|
+
}, [loading, users, usersError, rolesError]);
|
301
316
|
const isAdmin = roles.some((r) => r.id === "admin");
|
302
317
|
return {
|
303
318
|
loading,
|
@@ -369,6 +384,13 @@ const RoleYupSchema = Yup.object().shape({
|
|
369
384
|
id: Yup.string().required("Required"),
|
370
385
|
name: Yup.string().required("Required")
|
371
386
|
});
|
387
|
+
function canRoleBeEdited(loggedUser) {
|
388
|
+
const loggedUserIsAdmin = loggedUser.roles?.map((r) => r.id).includes("admin");
|
389
|
+
if (!loggedUserIsAdmin) {
|
390
|
+
throw new Error("Only admins can edit roles");
|
391
|
+
}
|
392
|
+
return true;
|
393
|
+
}
|
372
394
|
function RolesDetailsForm({
|
373
395
|
open,
|
374
396
|
role,
|
@@ -378,22 +400,34 @@ function RolesDetailsForm({
|
|
378
400
|
}) {
|
379
401
|
const { saveRole } = useUserManagement();
|
380
402
|
const isNewRole = !role;
|
403
|
+
const {
|
404
|
+
user: loggedInUser
|
405
|
+
} = useAuthController();
|
381
406
|
const [savingError, setSavingError] = useState();
|
382
407
|
const onRoleUpdated = useCallback((role2) => {
|
383
408
|
setSavingError(void 0);
|
409
|
+
if (!loggedInUser) throw new Error("User not found");
|
410
|
+
canRoleBeEdited(loggedInUser);
|
384
411
|
return saveRole(role2);
|
385
|
-
}, [saveRole]);
|
412
|
+
}, [saveRole, loggedInUser]);
|
386
413
|
const formex = useCreateFormex({
|
387
414
|
initialValues: role ?? {
|
388
415
|
name: ""
|
389
416
|
},
|
390
417
|
onSubmit: (role2, formexController) => {
|
391
|
-
|
392
|
-
|
393
|
-
|
418
|
+
try {
|
419
|
+
return onRoleUpdated(role2).then(() => {
|
420
|
+
formexController.resetForm({
|
421
|
+
values: role2
|
422
|
+
});
|
423
|
+
handleClose();
|
424
|
+
}).catch((e) => {
|
425
|
+
setSavingError(e);
|
394
426
|
});
|
395
|
-
|
396
|
-
|
427
|
+
} catch (e) {
|
428
|
+
setSavingError(e);
|
429
|
+
return Promise.resolve();
|
430
|
+
}
|
397
431
|
},
|
398
432
|
validation: (values2) => {
|
399
433
|
return RoleYupSchema.validate(values2, { abortEarly: false }).then(() => ({})).catch((e) => {
|
@@ -842,7 +876,7 @@ function RolesDetailsForm({
|
|
842
876
|
] })
|
843
877
|
] }),
|
844
878
|
/* @__PURE__ */ jsxs(DialogActions, { position: "sticky", children: [
|
845
|
-
savingError && /* @__PURE__ */ jsx(Typography, { className: "text-red-500", children: "There was an error saving this role" }),
|
879
|
+
savingError && /* @__PURE__ */ jsx(Typography, { className: "text-red-500 dark:text-red-500", children: savingError.message ?? "There was an error saving this role" }),
|
846
880
|
/* @__PURE__ */ jsx(
|
847
881
|
Button,
|
848
882
|
{
|