@firecms/user_management 3.0.0-canary.19 → 3.0.0-canary.191
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 +2179 -1216
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +2255 -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 +82 -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.191",
|
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.191",
|
33
|
+
"@firecms/formex": "^3.0.0-canary.191",
|
34
|
+
"@firecms/ui": "^3.0.0-canary.191",
|
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": "599f60d49fe738eca60a14df9ca577773acd4c1b"
|
60
|
+
"gitHead": "eec920b0db61ede54c9845a4e245a1f9b91d6298"
|
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,16 @@ 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
|
+
console.log("loggedUserIsAdmin", loggedUser);
|
37
|
+
if (!loggedUserIsAdmin) {
|
38
|
+
throw new Error("Only admins can edit roles");
|
39
|
+
}
|
40
|
+
|
41
|
+
return true;
|
42
|
+
}
|
43
|
+
|
33
44
|
export function RolesDetailsForm({
|
34
45
|
open,
|
35
46
|
role,
|
@@ -46,27 +57,39 @@ export function RolesDetailsForm({
|
|
46
57
|
|
47
58
|
const { saveRole } = useUserManagement();
|
48
59
|
const isNewRole = !role;
|
60
|
+
const {
|
61
|
+
user: loggedInUser
|
62
|
+
} = useAuthController();
|
49
63
|
|
50
64
|
const [savingError, setSavingError] = useState<Error | undefined>();
|
51
65
|
|
52
66
|
const onRoleUpdated = useCallback((role: Role) => {
|
53
67
|
setSavingError(undefined);
|
68
|
+
if (!loggedInUser) throw new Error("User not found");
|
69
|
+
canRoleBeEdited(loggedInUser);
|
54
70
|
return saveRole(role);
|
55
|
-
}, [saveRole]);
|
71
|
+
}, [saveRole, loggedInUser]);
|
56
72
|
|
57
73
|
const formex = useCreateFormex({
|
58
74
|
initialValues: role ?? {
|
59
75
|
name: ""
|
60
76
|
} as Role,
|
61
77
|
onSubmit: (role: Role, formexController) => {
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
78
|
+
try {
|
79
|
+
return onRoleUpdated(role)
|
80
|
+
.then(() => {
|
81
|
+
formexController.resetForm({
|
82
|
+
values: role
|
83
|
+
});
|
84
|
+
handleClose();
|
85
|
+
})
|
86
|
+
.catch(e => {
|
87
|
+
setSavingError(e);
|
66
88
|
});
|
67
|
-
|
68
|
-
|
69
|
-
.
|
89
|
+
} catch (e: any) {
|
90
|
+
setSavingError(e);
|
91
|
+
return Promise.resolve();
|
92
|
+
}
|
70
93
|
},
|
71
94
|
validation: (values) => {
|
72
95
|
return RoleYupSchema.validate(values, { abortEarly: false })
|
@@ -121,14 +144,10 @@ export function RolesDetailsForm({
|
|
121
144
|
position: "relative",
|
122
145
|
height: "100%"
|
123
146
|
}}>
|
147
|
+
<DialogTitle variant={"h4"} gutterBottom={false}>
|
148
|
+
Role
|
149
|
+
</DialogTitle>
|
124
150
|
<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
151
|
|
133
152
|
<div className={"grid grid-cols-12 gap-8"}>
|
134
153
|
|
@@ -168,11 +187,9 @@ export function RolesDetailsForm({
|
|
168
187
|
</div>
|
169
188
|
|
170
189
|
<div className={"col-span-12"}>
|
171
|
-
<Paper
|
172
|
-
|
173
|
-
|
174
|
-
<Table>
|
175
|
-
<TableHeader>
|
190
|
+
<Paper className="bg-inherit overflow-hidden">
|
191
|
+
<Table className={"w-full rounded-md"}>
|
192
|
+
<TableHeader className={"rounded-md"}>
|
176
193
|
<TableCell></TableCell>
|
177
194
|
<TableCell
|
178
195
|
align="center">Create
|
@@ -190,6 +207,9 @@ export function RolesDetailsForm({
|
|
190
207
|
align="center">Delete
|
191
208
|
entities
|
192
209
|
</TableCell>
|
210
|
+
<TableCell
|
211
|
+
align="center">
|
212
|
+
</TableCell>
|
193
213
|
</TableHeader>
|
194
214
|
|
195
215
|
<TableBody>
|
@@ -245,6 +265,9 @@ export function RolesDetailsForm({
|
|
245
265
|
|
246
266
|
</Tooltip>
|
247
267
|
</TableCell>
|
268
|
+
<TableCell
|
269
|
+
align="center">
|
270
|
+
</TableCell>
|
248
271
|
</TableRow>
|
249
272
|
{collections && collections.map((col) => (
|
250
273
|
<TableRow key={col.name}>
|
@@ -256,29 +279,49 @@ export function RolesDetailsForm({
|
|
256
279
|
align="center">
|
257
280
|
<Checkbox
|
258
281
|
disabled={isAdmin || defaultCreate || !editable}
|
259
|
-
checked={(isAdmin || defaultCreate || getIn(values, `collectionPermissions.${col.
|
260
|
-
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.
|
282
|
+
checked={(isAdmin || defaultCreate || getIn(values, `collectionPermissions.${col.id}.create`)) ?? false}
|
283
|
+
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.id}.create`, checked)}/>
|
261
284
|
</TableCell>
|
262
285
|
<TableCell
|
263
286
|
align="center">
|
264
287
|
<Checkbox
|
265
288
|
disabled={isAdmin || defaultRead || !editable}
|
266
|
-
checked={(isAdmin || defaultRead || getIn(values, `collectionPermissions.${col.
|
267
|
-
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.
|
289
|
+
checked={(isAdmin || defaultRead || getIn(values, `collectionPermissions.${col.id}.read`)) ?? false}
|
290
|
+
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.id}.read`, checked)}/>
|
268
291
|
</TableCell>
|
269
292
|
<TableCell
|
270
293
|
align="center">
|
271
294
|
<Checkbox
|
272
295
|
disabled={isAdmin || defaultEdit || !editable}
|
273
|
-
checked={(isAdmin || defaultEdit || getIn(values, `collectionPermissions.${col.
|
274
|
-
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.
|
296
|
+
checked={(isAdmin || defaultEdit || getIn(values, `collectionPermissions.${col.id}.edit`)) ?? false}
|
297
|
+
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.id}.edit`, checked)}/>
|
275
298
|
</TableCell>
|
276
299
|
<TableCell
|
277
300
|
align="center">
|
278
301
|
<Checkbox
|
279
302
|
disabled={isAdmin || defaultDelete || !editable}
|
280
|
-
checked={(isAdmin || defaultDelete || getIn(values, `collectionPermissions.${col.
|
281
|
-
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.
|
303
|
+
checked={(isAdmin || defaultDelete || getIn(values, `collectionPermissions.${col.id}.delete`)) ?? false}
|
304
|
+
onCheckedChange={(checked) => setFieldValue(`collectionPermissions.${col.id}.delete`, checked)}/>
|
305
|
+
</TableCell>
|
306
|
+
|
307
|
+
<TableCell
|
308
|
+
align="center">
|
309
|
+
<Tooltip
|
310
|
+
title="Allow all permissions in this collections">
|
311
|
+
<Button
|
312
|
+
className={"color-inherit"}
|
313
|
+
onClick={() => {
|
314
|
+
setFieldValue(`collectionPermissions.${col.id}.create`, true);
|
315
|
+
setFieldValue(`collectionPermissions.${col.id}.read`, true);
|
316
|
+
setFieldValue(`collectionPermissions.${col.id}.edit`, true);
|
317
|
+
setFieldValue(`collectionPermissions.${col.id}.delete`, true);
|
318
|
+
}}
|
319
|
+
disabled={isAdmin || !editable}
|
320
|
+
variant={"text"}>
|
321
|
+
All
|
322
|
+
</Button>
|
323
|
+
|
324
|
+
</Tooltip>
|
282
325
|
</TableCell>
|
283
326
|
</TableRow>
|
284
327
|
))}
|
@@ -296,6 +339,8 @@ export function RolesDetailsForm({
|
|
296
339
|
<div className={"col-span-12 md:col-span-4"}>
|
297
340
|
<Select
|
298
341
|
error={touched.config && Boolean(errors.config)}
|
342
|
+
size={"large"}
|
343
|
+
fullWidth={true}
|
299
344
|
id="createCollections"
|
300
345
|
name="createCollections"
|
301
346
|
label="Create collections"
|
@@ -318,6 +363,8 @@ export function RolesDetailsForm({
|
|
318
363
|
|
319
364
|
<div className={"col-span-12 md:col-span-4"}>
|
320
365
|
<Select
|
366
|
+
size={"large"}
|
367
|
+
fullWidth={true}
|
321
368
|
error={touched.config && Boolean(errors.config)}
|
322
369
|
id="editCollections"
|
323
370
|
name="editCollections"
|
@@ -344,6 +391,8 @@ export function RolesDetailsForm({
|
|
344
391
|
|
345
392
|
<div className={"col-span-12 md:col-span-4"}>
|
346
393
|
<Select
|
394
|
+
size={"large"}
|
395
|
+
fullWidth={true}
|
347
396
|
error={touched.config && Boolean(errors.config)}
|
348
397
|
id="deleteCollections"
|
349
398
|
name="deleteCollections"
|
@@ -373,8 +422,8 @@ export function RolesDetailsForm({
|
|
373
422
|
</DialogContent>
|
374
423
|
|
375
424
|
<DialogActions position={"sticky"}>
|
376
|
-
{savingError && <Typography className={"text-red-500"}>
|
377
|
-
There was an error saving this role
|
425
|
+
{savingError && <Typography className={"text-red-500 dark:text-red-500"}>
|
426
|
+
{savingError.message ?? "There was an error saving this role"}
|
378
427
|
</Typography>}
|
379
428
|
<Button variant={"text"}
|
380
429
|
onClick={() => {
|
@@ -388,7 +437,7 @@ export function RolesDetailsForm({
|
|
388
437
|
type="submit"
|
389
438
|
disabled={!dirty}
|
390
439
|
loading={isSubmitting}
|
391
|
-
startIcon={<
|
440
|
+
startIcon={<CheckIcon/>}
|
392
441
|
>
|
393
442
|
{isNewRole ? "Create role" : "Update"}
|
394
443
|
</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";
|