@firecms/user_management 3.0.0-canary.23 → 3.0.0-canary.231
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/README.md +2 -2
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/{useBuildFirestoreUserManagement.d.ts → useBuildUserManagement.d.ts} +11 -12
- package/dist/index.es.js +2178 -1216
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +2254 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/types/user_management.d.ts +6 -12
- package/dist/useUserManagementPlugin.d.ts +8 -3
- package/dist/utils/permissions.d.ts +2 -2
- package/package.json +14 -28
- package/src/components/roles/RolesDetailsForm.tsx +81 -33
- package/src/components/roles/RolesTable.tsx +6 -4
- package/src/components/roles/RolesView.tsx +9 -15
- package/src/components/users/UserDetailsForm.tsx +18 -19
- package/src/components/users/UsersTable.tsx +6 -6
- package/src/components/users/UsersView.tsx +1 -4
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useBuildUserManagement.tsx +333 -0
- package/src/types/user_management.tsx +7 -13
- package/src/useUserManagementPlugin.tsx +89 -3
- package/src/utils/permissions.ts +9 -8
- package/src/hooks/useBuildFirestoreUserManagement.tsx +0 -271
@@ -1,5 +1,6 @@
|
|
1
1
|
import { Authenticator, PermissionsBuilder, Role, User } from "@firecms/core";
|
2
2
|
export type UserManagement<USER extends User = User> = {
|
3
|
+
authenticator?: Authenticator<USER>;
|
3
4
|
loading: boolean;
|
4
5
|
users: USER[];
|
5
6
|
saveUser: (user: USER) => Promise<USER>;
|
@@ -8,13 +9,9 @@ export type UserManagement<USER extends User = User> = {
|
|
8
9
|
saveRole: (role: Role) => Promise<void>;
|
9
10
|
deleteRole: (role: Role) => Promise<void>;
|
10
11
|
/**
|
11
|
-
*
|
12
|
+
* Is the logged user Admin?
|
12
13
|
*/
|
13
|
-
|
14
|
-
/**
|
15
|
-
* Can the logged user edit roles?
|
16
|
-
*/
|
17
|
-
canEditRoles?: boolean;
|
14
|
+
isAdmin?: boolean;
|
18
15
|
/**
|
19
16
|
* Include a button to create default roles, in case there are no roles in the system.
|
20
17
|
*/
|
@@ -32,10 +29,7 @@ export type UserManagement<USER extends User = User> = {
|
|
32
29
|
* Define the roles for a given user. You will typically want to plug this into your auth controller.
|
33
30
|
* @param user
|
34
31
|
*/
|
35
|
-
defineRolesFor: (user: User) => Promise<Role[]> | Role[] | undefined;
|
36
|
-
|
37
|
-
|
38
|
-
* It will only allow access to users with the required roles.
|
39
|
-
*/
|
40
|
-
authenticator?: Authenticator;
|
32
|
+
defineRolesFor: (user: User) => Promise<Role[] | undefined> | Role[] | undefined;
|
33
|
+
rolesError?: Error;
|
34
|
+
usersError?: Error;
|
41
35
|
};
|
@@ -1,5 +1,10 @@
|
|
1
|
-
import { FireCMSPlugin } from "@firecms/core";
|
1
|
+
import { FireCMSPlugin, User } from "@firecms/core";
|
2
2
|
import { UserManagement } from "./types";
|
3
|
-
export declare function useUserManagementPlugin({ userManagement }: {
|
4
|
-
userManagement: UserManagement
|
3
|
+
export declare function useUserManagementPlugin<USER extends User = any>({ userManagement }: {
|
4
|
+
userManagement: UserManagement<USER>;
|
5
5
|
}): FireCMSPlugin;
|
6
|
+
export declare function IntroWidget({ noUsers, noRoles, userManagement }: {
|
7
|
+
noUsers: boolean;
|
8
|
+
noRoles: boolean;
|
9
|
+
userManagement: UserManagement<any>;
|
10
|
+
}): import("react/jsx-runtime").JSX.Element;
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import { EntityCollection, Permissions, Role, User } from "@firecms/core";
|
2
2
|
export declare const RESERVED_GROUPS: string[];
|
3
|
-
export declare function resolveUserRolePermissions<
|
3
|
+
export declare function resolveUserRolePermissions<USER extends User>({ collection, user }: {
|
4
4
|
collection: EntityCollection<any>;
|
5
|
-
user:
|
5
|
+
user: USER | null;
|
6
6
|
}): Permissions;
|
7
7
|
export declare function getUserRoles(roles: Role[], fireCMSUser: User): Role[] | undefined;
|
8
8
|
export declare const areRolesEqual: (rolesA: Role[], rolesB: Role[]) => boolean;
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@firecms/user_management",
|
3
3
|
"type": "module",
|
4
|
-
"version": "3.0.0-canary.
|
4
|
+
"version": "3.0.0-canary.231",
|
5
5
|
"publishConfig": {
|
6
6
|
"access": "public"
|
7
7
|
},
|
@@ -24,36 +24,28 @@
|
|
24
24
|
},
|
25
25
|
"./package.json": "./package.json"
|
26
26
|
},
|
27
|
-
"packageManager": "yarn@4.1.0",
|
28
27
|
"main": "./dist/index.umd.js",
|
29
28
|
"module": "./dist/index.es.js",
|
30
29
|
"types": "dist/index.d.ts",
|
31
30
|
"source": "src/index.ts",
|
32
31
|
"dependencies": {
|
33
|
-
"@firecms/core": "^3.0.0-canary.
|
34
|
-
"@firecms/formex": "^3.0.0-canary.
|
35
|
-
"@firecms/ui": "^3.0.0-canary.
|
32
|
+
"@firecms/core": "^3.0.0-canary.231",
|
33
|
+
"@firecms/formex": "^3.0.0-canary.231",
|
34
|
+
"@firecms/ui": "^3.0.0-canary.231",
|
36
35
|
"date-fns": "^3.6.0"
|
37
36
|
},
|
38
37
|
"peerDependencies": {
|
39
|
-
"
|
40
|
-
"react": "
|
41
|
-
"react-dom": "^18.2.0"
|
38
|
+
"react": ">=18.0.0",
|
39
|
+
"react-dom": ">=18.0.0"
|
42
40
|
},
|
43
41
|
"devDependencies": {
|
44
|
-
"@types/node": "^20.
|
45
|
-
"@types/react": "^18.
|
46
|
-
"@types/react-dom": "^18.
|
47
|
-
"
|
48
|
-
"eslint": "
|
49
|
-
"
|
50
|
-
"
|
51
|
-
"eslint-plugin-n": "^16.6.2",
|
52
|
-
"eslint-plugin-promise": "^6.1.1",
|
53
|
-
"eslint-plugin-react": "^7.34.1",
|
54
|
-
"eslint-plugin-react-hooks": "^4.6.0",
|
55
|
-
"typescript": "^5.4.2",
|
56
|
-
"vite": "^5.2.3"
|
42
|
+
"@types/node": "^20.17.14",
|
43
|
+
"@types/react": "^18.3.18",
|
44
|
+
"@types/react-dom": "^18.3.0",
|
45
|
+
"babel-plugin-react-compiler": "beta",
|
46
|
+
"eslint-plugin-react-compiler": "beta",
|
47
|
+
"typescript": "^5.7.3",
|
48
|
+
"vite": "^5.4.14"
|
57
49
|
},
|
58
50
|
"scripts": {
|
59
51
|
"dev": "vite",
|
@@ -65,11 +57,5 @@
|
|
65
57
|
"src",
|
66
58
|
"bin"
|
67
59
|
],
|
68
|
-
"
|
69
|
-
"extends": [
|
70
|
-
"react-app",
|
71
|
-
"react-app/jest"
|
72
|
-
]
|
73
|
-
},
|
74
|
-
"gitHead": "c8d7ad2f2d5f2ac8efc118d1588c47e38fd14559"
|
60
|
+
"gitHead": "c38a44b87565537d51e654a0565b0921c933c55e"
|
75
61
|
}
|
@@ -1,14 +1,15 @@
|
|
1
1
|
import React, { useCallback, useState } from "react";
|
2
2
|
import * as Yup from "yup";
|
3
3
|
|
4
|
-
import { EntityCollection, FieldCaption, Role, toSnakeCase, } from "@firecms/core";
|
4
|
+
import { EntityCollection, FieldCaption, Role, toSnakeCase, useAuthController, User, } from "@firecms/core";
|
5
5
|
import {
|
6
6
|
Button,
|
7
7
|
Checkbox,
|
8
|
+
CheckIcon,
|
8
9
|
Dialog,
|
9
10
|
DialogActions,
|
10
11
|
DialogContent,
|
11
|
-
|
12
|
+
DialogTitle,
|
12
13
|
LoadingButton,
|
13
14
|
Paper,
|
14
15
|
Select,
|
@@ -30,6 +31,15 @@ export const RoleYupSchema = Yup.object().shape({
|
|
30
31
|
name: Yup.string().required("Required")
|
31
32
|
});
|
32
33
|
|
34
|
+
function canRoleBeEdited(loggedUser: User) {
|
35
|
+
const loggedUserIsAdmin = loggedUser.roles?.map(r => r.id).includes("admin");
|
36
|
+
if (!loggedUserIsAdmin) {
|
37
|
+
throw new Error("Only admins can edit roles");
|
38
|
+
}
|
39
|
+
|
40
|
+
return true;
|
41
|
+
}
|
42
|
+
|
33
43
|
export function RolesDetailsForm({
|
34
44
|
open,
|
35
45
|
role,
|
@@ -46,27 +56,39 @@ export function RolesDetailsForm({
|
|
46
56
|
|
47
57
|
const { saveRole } = useUserManagement();
|
48
58
|
const isNewRole = !role;
|
59
|
+
const {
|
60
|
+
user: loggedInUser
|
61
|
+
} = useAuthController();
|
49
62
|
|
50
63
|
const [savingError, setSavingError] = useState<Error | undefined>();
|
51
64
|
|
52
65
|
const onRoleUpdated = useCallback((role: Role) => {
|
53
66
|
setSavingError(undefined);
|
67
|
+
if (!loggedInUser) throw new Error("User not found");
|
68
|
+
canRoleBeEdited(loggedInUser);
|
54
69
|
return saveRole(role);
|
55
|
-
}, [saveRole]);
|
70
|
+
}, [saveRole, loggedInUser]);
|
56
71
|
|
57
72
|
const formex = useCreateFormex({
|
58
73
|
initialValues: role ?? {
|
59
74
|
name: ""
|
60
75
|
} as Role,
|
61
76
|
onSubmit: (role: Role, formexController) => {
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
77
|
+
try {
|
78
|
+
return onRoleUpdated(role)
|
79
|
+
.then(() => {
|
80
|
+
formexController.resetForm({
|
81
|
+
values: role
|
82
|
+
});
|
83
|
+
handleClose();
|
84
|
+
})
|
85
|
+
.catch(e => {
|
86
|
+
setSavingError(e);
|
66
87
|
});
|
67
|
-
|
68
|
-
|
69
|
-
.
|
88
|
+
} catch (e: any) {
|
89
|
+
setSavingError(e);
|
90
|
+
return Promise.resolve();
|
91
|
+
}
|
70
92
|
},
|
71
93
|
validation: (values) => {
|
72
94
|
return RoleYupSchema.validate(values, { abortEarly: false })
|
@@ -121,14 +143,10 @@ export function RolesDetailsForm({
|
|
121
143
|
position: "relative",
|
122
144
|
height: "100%"
|
123
145
|
}}>
|
146
|
+
<DialogTitle variant={"h4"} gutterBottom={false}>
|
147
|
+
Role
|
148
|
+
</DialogTitle>
|
124
149
|
<DialogContent className="flex-grow">
|
125
|
-
<div
|
126
|
-
className="flex flex-row pt-12 pb-8">
|
127
|
-
<Typography variant={"h4"}
|
128
|
-
className="flex-grow">
|
129
|
-
Role
|
130
|
-
</Typography>
|
131
|
-
</div>
|
132
150
|
|
133
151
|
<div className={"grid grid-cols-12 gap-8"}>
|
134
152
|
|
@@ -168,11 +186,9 @@ export function RolesDetailsForm({
|
|
168
186
|
</div>
|
169
187
|
|
170
188
|
<div className={"col-span-12"}>
|
171
|
-
<Paper
|
172
|
-
|
173
|
-
|
174
|
-
<Table>
|
175
|
-
<TableHeader>
|
189
|
+
<Paper className="bg-inherit overflow-hidden">
|
190
|
+
<Table className={"w-full rounded-md"}>
|
191
|
+
<TableHeader className={"rounded-md"}>
|
176
192
|
<TableCell></TableCell>
|
177
193
|
<TableCell
|
178
194
|
align="center">Create
|
@@ -190,6 +206,9 @@ export function RolesDetailsForm({
|
|
190
206
|
align="center">Delete
|
191
207
|
entities
|
192
208
|
</TableCell>
|
209
|
+
<TableCell
|
210
|
+
align="center">
|
211
|
+
</TableCell>
|
193
212
|
</TableHeader>
|
194
213
|
|
195
214
|
<TableBody>
|
@@ -245,6 +264,9 @@ export function RolesDetailsForm({
|
|
245
264
|
|
246
265
|
</Tooltip>
|
247
266
|
</TableCell>
|
267
|
+
<TableCell
|
268
|
+
align="center">
|
269
|
+
</TableCell>
|
248
270
|
</TableRow>
|
249
271
|
{collections && collections.map((col) => (
|
250
272
|
<TableRow key={col.name}>
|
@@ -256,29 +278,49 @@ export function RolesDetailsForm({
|
|
256
278
|
align="center">
|
257
279
|
<Checkbox
|
258
280
|
disabled={isAdmin || defaultCreate || !editable}
|
259
|
-
checked={(isAdmin || defaultCreate || getIn(values, `collectionPermissions.${col.
|
260
|
-
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.
|
281
|
+
checked={(isAdmin || defaultCreate || getIn(values, `collectionPermissions.${col.id}.create`)) ?? false}
|
282
|
+
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.id}.create`, checked)}/>
|
261
283
|
</TableCell>
|
262
284
|
<TableCell
|
263
285
|
align="center">
|
264
286
|
<Checkbox
|
265
287
|
disabled={isAdmin || defaultRead || !editable}
|
266
|
-
checked={(isAdmin || defaultRead || getIn(values, `collectionPermissions.${col.
|
267
|
-
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.
|
288
|
+
checked={(isAdmin || defaultRead || getIn(values, `collectionPermissions.${col.id}.read`)) ?? false}
|
289
|
+
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.id}.read`, checked)}/>
|
268
290
|
</TableCell>
|
269
291
|
<TableCell
|
270
292
|
align="center">
|
271
293
|
<Checkbox
|
272
294
|
disabled={isAdmin || defaultEdit || !editable}
|
273
|
-
checked={(isAdmin || defaultEdit || getIn(values, `collectionPermissions.${col.
|
274
|
-
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.
|
295
|
+
checked={(isAdmin || defaultEdit || getIn(values, `collectionPermissions.${col.id}.edit`)) ?? false}
|
296
|
+
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.id}.edit`, checked)}/>
|
275
297
|
</TableCell>
|
276
298
|
<TableCell
|
277
299
|
align="center">
|
278
300
|
<Checkbox
|
279
301
|
disabled={isAdmin || defaultDelete || !editable}
|
280
|
-
checked={(isAdmin || defaultDelete || getIn(values, `collectionPermissions.${col.
|
281
|
-
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.
|
302
|
+
checked={(isAdmin || defaultDelete || getIn(values, `collectionPermissions.${col.id}.delete`)) ?? false}
|
303
|
+
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.id}.delete`, checked)}/>
|
304
|
+
</TableCell>
|
305
|
+
|
306
|
+
<TableCell
|
307
|
+
align="center">
|
308
|
+
<Tooltip
|
309
|
+
title="Allow all permissions in this collections">
|
310
|
+
<Button
|
311
|
+
className={"color-inherit"}
|
312
|
+
onClick={() => {
|
313
|
+
setFieldValue(`collectionPermissions.${col.id}.create`, true);
|
314
|
+
setFieldValue(`collectionPermissions.${col.id}.read`, true);
|
315
|
+
setFieldValue(`collectionPermissions.${col.id}.edit`, true);
|
316
|
+
setFieldValue(`collectionPermissions.${col.id}.delete`, true);
|
317
|
+
}}
|
318
|
+
disabled={isAdmin || !editable}
|
319
|
+
variant={"text"}>
|
320
|
+
All
|
321
|
+
</Button>
|
322
|
+
|
323
|
+
</Tooltip>
|
282
324
|
</TableCell>
|
283
325
|
</TableRow>
|
284
326
|
))}
|
@@ -296,6 +338,8 @@ export function RolesDetailsForm({
|
|
296
338
|
<div className={"col-span-12 md:col-span-4"}>
|
297
339
|
<Select
|
298
340
|
error={touched.config && Boolean(errors.config)}
|
341
|
+
size={"large"}
|
342
|
+
fullWidth={true}
|
299
343
|
id="createCollections"
|
300
344
|
name="createCollections"
|
301
345
|
label="Create collections"
|
@@ -318,6 +362,8 @@ export function RolesDetailsForm({
|
|
318
362
|
|
319
363
|
<div className={"col-span-12 md:col-span-4"}>
|
320
364
|
<Select
|
365
|
+
size={"large"}
|
366
|
+
fullWidth={true}
|
321
367
|
error={touched.config && Boolean(errors.config)}
|
322
368
|
id="editCollections"
|
323
369
|
name="editCollections"
|
@@ -344,6 +390,8 @@ export function RolesDetailsForm({
|
|
344
390
|
|
345
391
|
<div className={"col-span-12 md:col-span-4"}>
|
346
392
|
<Select
|
393
|
+
size={"large"}
|
394
|
+
fullWidth={true}
|
347
395
|
error={touched.config && Boolean(errors.config)}
|
348
396
|
id="deleteCollections"
|
349
397
|
name="deleteCollections"
|
@@ -373,8 +421,8 @@ export function RolesDetailsForm({
|
|
373
421
|
</DialogContent>
|
374
422
|
|
375
423
|
<DialogActions position={"sticky"}>
|
376
|
-
{savingError && <Typography className={"text-red-500"}>
|
377
|
-
There was an error saving this role
|
424
|
+
{savingError && <Typography className={"text-red-500 dark:text-red-500"}>
|
425
|
+
{savingError.message ?? "There was an error saving this role"}
|
378
426
|
</Typography>}
|
379
427
|
<Button variant={"text"}
|
380
428
|
onClick={() => {
|
@@ -388,7 +436,7 @@ export function RolesDetailsForm({
|
|
388
436
|
type="submit"
|
389
437
|
disabled={!dirty}
|
390
438
|
loading={isSubmitting}
|
391
|
-
startIcon={<
|
439
|
+
startIcon={<CheckIcon/>}
|
392
440
|
>
|
393
441
|
{isNewRole ? "Create role" : "Update"}
|
394
442
|
</LoadingButton>
|
@@ -13,7 +13,7 @@ import {
|
|
13
13
|
Tooltip,
|
14
14
|
Typography
|
15
15
|
} from "@firecms/ui";
|
16
|
-
import {
|
16
|
+
import { ConfirmationDialog, Role } from "@firecms/core";
|
17
17
|
import { useUserManagement } from "../../hooks";
|
18
18
|
import { RoleChip } from "./RoleChip";
|
19
19
|
import { DEFAULT_ROLES } from "./default_roles";
|
@@ -38,7 +38,7 @@ export function RolesTable({
|
|
38
38
|
|
39
39
|
return <div
|
40
40
|
className="w-full overflow-auto">
|
41
|
-
<Table>
|
41
|
+
<Table className={"w-full"}>
|
42
42
|
<TableHeader>
|
43
43
|
<TableCell header={true} className="w-16"></TableCell>
|
44
44
|
<TableCell header={true}>Role</TableCell>
|
@@ -61,7 +61,9 @@ export function RolesTable({
|
|
61
61
|
>
|
62
62
|
<TableCell style={{ width: "64px" }}>
|
63
63
|
{!role.isAdmin &&
|
64
|
-
<Tooltip
|
64
|
+
<Tooltip
|
65
|
+
asChild={true}
|
66
|
+
title={"Delete this role"}>
|
65
67
|
<IconButton
|
66
68
|
size={"small"}
|
67
69
|
disabled={!editable}
|
@@ -113,7 +115,7 @@ export function RolesTable({
|
|
113
115
|
|
114
116
|
</Table>
|
115
117
|
|
116
|
-
<
|
118
|
+
<ConfirmationDialog
|
117
119
|
open={Boolean(roleToBeDeleted)}
|
118
120
|
loading={deleteInProgress}
|
119
121
|
onAccept={() => {
|
@@ -1,10 +1,9 @@
|
|
1
1
|
import React, { useCallback, useState } from "react";
|
2
2
|
|
3
3
|
import { Role, useNavigationController } from "@firecms/core";
|
4
|
-
import { AddIcon, Button, Container,
|
4
|
+
import { AddIcon, Button, Container, Typography } from "@firecms/ui";
|
5
5
|
import { RolesTable } from "./RolesTable";
|
6
6
|
import { RolesDetailsForm } from "./RolesDetailsForm";
|
7
|
-
import { useUserManagement } from "../../hooks";
|
8
7
|
|
9
8
|
export const RolesView = React.memo(
|
10
9
|
function RolesView({ children }: { children?: React.ReactNode }) {
|
@@ -13,8 +12,6 @@ export const RolesView = React.memo(
|
|
13
12
|
const [dialogOpen, setDialogOpen] = useState(false);
|
14
13
|
const [selectedRole, setSelectedRole] = useState<Role | undefined>();
|
15
14
|
|
16
|
-
const { canEditRoles } = useUserManagement();
|
17
|
-
|
18
15
|
const onRoleClicked = useCallback((user: Role) => {
|
19
16
|
setDialogOpen(true);
|
20
17
|
setSelectedRole(user);
|
@@ -36,24 +33,21 @@ export const RolesView = React.memo(
|
|
36
33
|
component="h4">
|
37
34
|
Roles
|
38
35
|
</Typography>
|
39
|
-
<
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
Add role
|
46
|
-
</Button>
|
47
|
-
</Tooltip>
|
36
|
+
<Button
|
37
|
+
size={"large"}
|
38
|
+
startIcon={<AddIcon/>}
|
39
|
+
onClick={() => setDialogOpen(true)}>
|
40
|
+
Add role
|
41
|
+
</Button>
|
48
42
|
</div>
|
49
43
|
|
50
|
-
<RolesTable onRoleClicked={onRoleClicked} editable={
|
44
|
+
<RolesTable onRoleClicked={onRoleClicked} editable={true}/>
|
51
45
|
|
52
46
|
<RolesDetailsForm
|
53
47
|
key={selectedRole?.id ?? "new"}
|
54
48
|
open={dialogOpen}
|
55
49
|
role={selectedRole}
|
56
|
-
editable={
|
50
|
+
editable={true}
|
57
51
|
collections={collections}
|
58
52
|
handleClose={handleClose}/>
|
59
53
|
|
@@ -2,15 +2,15 @@ import React, { useCallback } from "react";
|
|
2
2
|
import * as Yup from "yup";
|
3
3
|
import {
|
4
4
|
Button,
|
5
|
+
CheckIcon,
|
5
6
|
Dialog,
|
6
7
|
DialogActions,
|
7
8
|
DialogContent,
|
8
|
-
|
9
|
+
DialogTitle,
|
9
10
|
LoadingButton,
|
10
11
|
MultiSelect,
|
11
12
|
MultiSelectItem,
|
12
13
|
TextField,
|
13
|
-
Typography,
|
14
14
|
} from "@firecms/ui";
|
15
15
|
import { FieldCaption, Role, useAuthController, User, useSnackbarController } from "@firecms/core";
|
16
16
|
import { Formex, useCreateFormex } from "@firecms/formex";
|
@@ -140,14 +140,11 @@ export function UserDetailsForm({
|
|
140
140
|
position: "relative",
|
141
141
|
height: "100%"
|
142
142
|
}}>
|
143
|
+
|
144
|
+
<DialogTitle variant={"h4"} gutterBottom={false}>
|
145
|
+
User
|
146
|
+
</DialogTitle>
|
143
147
|
<DialogContent className="h-full flex-grow">
|
144
|
-
<div
|
145
|
-
className="flex flex-row pt-4 pb-4">
|
146
|
-
<Typography variant={"h4"}
|
147
|
-
className="flex-grow">
|
148
|
-
User
|
149
|
-
</Typography>
|
150
|
-
</div>
|
151
148
|
|
152
149
|
<div className={"grid grid-cols-12 gap-8"}>
|
153
150
|
|
@@ -181,17 +178,19 @@ export function UserDetailsForm({
|
|
181
178
|
</div>
|
182
179
|
<div className={"col-span-12"}>
|
183
180
|
<MultiSelect
|
181
|
+
className={"w-full"}
|
184
182
|
label="Roles"
|
185
183
|
value={values.roles?.map(r => r.id) ?? []}
|
186
|
-
|
187
|
-
renderValue={(value: string) => {
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
}}
|
184
|
+
onValueChange={(value: string[]) => setFieldValue("roles", value.map(id => roles.find(r => r.id === id) as Role))}
|
185
|
+
// renderValue={(value: string) => {
|
186
|
+
// const userRole = roles
|
187
|
+
// .find((role) => role.id === value);
|
188
|
+
// if (!userRole) return null;
|
189
|
+
// return <div className="flex flex-wrap space-x-2 space-y-2">
|
190
|
+
// <RoleChip key={userRole?.id} role={userRole}/>
|
191
|
+
// </div>;
|
192
|
+
// }}
|
193
|
+
>
|
195
194
|
{roles.map(userRole => <MultiSelectItem key={userRole.id}
|
196
195
|
value={userRole.id}>
|
197
196
|
<RoleChip key={userRole?.id} role={userRole}/>
|
@@ -218,7 +217,7 @@ export function UserDetailsForm({
|
|
218
217
|
type="submit"
|
219
218
|
disabled={!dirty}
|
220
219
|
loading={isSubmitting}
|
221
|
-
startIcon={<
|
220
|
+
startIcon={<CheckIcon/>}
|
222
221
|
>
|
223
222
|
{isNewUser ? "Create user" : "Update"}
|
224
223
|
</LoadingButton>
|
@@ -5,7 +5,7 @@ import * as locales from "date-fns/locale";
|
|
5
5
|
|
6
6
|
import {
|
7
7
|
defaultDateFormat,
|
8
|
-
|
8
|
+
ConfirmationDialog, Role,
|
9
9
|
useAuthController,
|
10
10
|
useCustomizationController, User,
|
11
11
|
useSnackbarController
|
@@ -50,11 +50,10 @@ export function UsersTable({ onUserClicked }: {
|
|
50
50
|
return (
|
51
51
|
<div className="overflow-auto">
|
52
52
|
|
53
|
-
<Table>
|
53
|
+
<Table className={"w-full"}>
|
54
54
|
|
55
55
|
<TableHeader>
|
56
56
|
<TableCell className="truncate w-16"></TableCell>
|
57
|
-
<TableCell>ID</TableCell>
|
58
57
|
<TableCell>Email</TableCell>
|
59
58
|
<TableCell>Name</TableCell>
|
60
59
|
<TableCell>Roles</TableCell>
|
@@ -75,7 +74,9 @@ export function UsersTable({ onUserClicked }: {
|
|
75
74
|
}}
|
76
75
|
>
|
77
76
|
<TableCell className={"w-10"}>
|
78
|
-
<Tooltip
|
77
|
+
<Tooltip
|
78
|
+
asChild={true}
|
79
|
+
title={"Delete this user"}>
|
79
80
|
<IconButton
|
80
81
|
size={"small"}
|
81
82
|
onClick={(event) => {
|
@@ -86,7 +87,6 @@ export function UsersTable({ onUserClicked }: {
|
|
86
87
|
</IconButton>
|
87
88
|
</Tooltip>
|
88
89
|
</TableCell>
|
89
|
-
<TableCell>{user.uid}</TableCell>
|
90
90
|
<TableCell>{user.email}</TableCell>
|
91
91
|
<TableCell className={"font-medium align-left"}>{user.displayName}</TableCell>
|
92
92
|
<TableCell className="align-left">
|
@@ -147,7 +147,7 @@ export function UsersTable({ onUserClicked }: {
|
|
147
147
|
</TableBody>
|
148
148
|
</Table>
|
149
149
|
|
150
|
-
<
|
150
|
+
<ConfirmationDialog
|
151
151
|
open={Boolean(userToBeDeleted)}
|
152
152
|
loading={deleteInProgress}
|
153
153
|
onAccept={() => {
|
@@ -11,9 +11,7 @@ export const UsersView = function UsersView({ children }: { children?: React.Rea
|
|
11
11
|
const [dialogOpen, setDialogOpen] = useState<boolean>();
|
12
12
|
const [selectedUser, setSelectedUser] = useState<User | undefined>();
|
13
13
|
|
14
|
-
const { users
|
15
|
-
|
16
|
-
const reachedUsersLimit = usersLimit !== undefined && (users && users.length >= usersLimit);
|
14
|
+
const { users } = useUserManagement();
|
17
15
|
|
18
16
|
const onUserClicked = useCallback((user: User) => {
|
19
17
|
setSelectedUser(user);
|
@@ -39,7 +37,6 @@ export const UsersView = function UsersView({ children }: { children?: React.Rea
|
|
39
37
|
</Typography>
|
40
38
|
<Button
|
41
39
|
size={"large"}
|
42
|
-
disabled={reachedUsersLimit}
|
43
40
|
startIcon={<AddIcon/>}
|
44
41
|
onClick={() => setDialogOpen(true)}>
|
45
42
|
Add user
|
package/src/hooks/index.ts
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
export * from "./
|
1
|
+
export * from "./useBuildUserManagement";
|
2
2
|
export * from "./useUserManagement";
|