@firecms/user_management 3.0.0-canary.84 → 3.0.0-canary.86
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/hooks/index.d.ts +1 -1
- package/dist/hooks/{useFirestoreUserManagement.d.ts → useBuildUserManagement.d.ts} +8 -7
- package/dist/index.es.js +99 -81
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +97 -79
- package/dist/index.umd.js.map +1 -1
- package/package.json +8 -9
- package/src/hooks/index.ts +1 -1
- package/src/hooks/{useFirestoreUserManagement.tsx → useBuildUserManagement.tsx} +115 -97
@@ -1,33 +1,25 @@
|
|
1
1
|
import React, { useCallback, useEffect } from "react";
|
2
|
-
import
|
3
|
-
|
4
|
-
collection,
|
5
|
-
deleteDoc,
|
6
|
-
doc,
|
7
|
-
DocumentSnapshot,
|
8
|
-
getFirestore,
|
9
|
-
onSnapshot,
|
10
|
-
setDoc
|
11
|
-
} from "@firebase/firestore";
|
12
|
-
import { FirebaseApp } from "@firebase/app";
|
2
|
+
import equal from "react-fast-compare"
|
3
|
+
|
13
4
|
import { UserManagement } from "../types";
|
14
|
-
import { Authenticator, PermissionsBuilder, Role, User } from "@firecms/core";
|
5
|
+
import { Authenticator, DataSourceDelegate, Entity, PermissionsBuilder, Role, User } from "@firecms/core";
|
15
6
|
import { resolveUserRolePermissions } from "../utils";
|
16
7
|
|
17
8
|
type UserWithRoleIds = User & { roles: string[] };
|
18
9
|
|
19
10
|
export interface UserManagementParams {
|
11
|
+
|
20
12
|
/**
|
21
|
-
* The
|
22
|
-
* collection indicated by `configPath`.
|
13
|
+
* The delegate in charge of persisting the data.
|
23
14
|
*/
|
24
|
-
|
15
|
+
dataSourceDelegate?: DataSourceDelegate;
|
16
|
+
|
25
17
|
/**
|
26
18
|
* Path where the plugin users configuration is stored.
|
27
19
|
* Default: __FIRECMS/config/users
|
28
20
|
* You can specify a different path if you want to store the user management configuration in a different place.
|
29
21
|
* Please keep in mind that the FireCMS users are not necessarily the same as the Firebase users (but they can be).
|
30
|
-
* The path should be relative to the root of the
|
22
|
+
* The path should be relative to the root of the database, and should always have an odd number of segments.
|
31
23
|
*/
|
32
24
|
usersPath?: string;
|
33
25
|
|
@@ -62,21 +54,23 @@ export interface UserManagementParams {
|
|
62
54
|
/**
|
63
55
|
* This hook is used to build a user management object that can be used to
|
64
56
|
* manage users and roles in a Firestore backend.
|
65
|
-
* @param
|
57
|
+
* @param dataSourceDelegate
|
66
58
|
* @param usersPath
|
67
59
|
* @param rolesPath
|
68
60
|
* @param usersLimit
|
69
61
|
* @param canEditRoles
|
62
|
+
* @param allowDefaultRolesCreation
|
63
|
+
* @param includeCollectionConfigPermissions
|
70
64
|
*/
|
71
|
-
export function
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
65
|
+
export function useBuildUserManagement({
|
66
|
+
dataSourceDelegate,
|
67
|
+
usersPath = "__FIRECMS/config/users",
|
68
|
+
rolesPath = "__FIRECMS/config/roles",
|
69
|
+
usersLimit,
|
70
|
+
canEditRoles = true,
|
71
|
+
allowDefaultRolesCreation,
|
72
|
+
includeCollectionConfigPermissions
|
73
|
+
}: UserManagementParams): UserManagement {
|
80
74
|
|
81
75
|
const [rolesLoading, setRolesLoading] = React.useState<boolean>(true);
|
82
76
|
const [usersLoading, setUsersLoading] = React.useState<boolean>(true);
|
@@ -94,62 +88,65 @@ export function useFirestoreUserManagement({
|
|
94
88
|
const loading = rolesLoading || usersLoading;
|
95
89
|
|
96
90
|
useEffect(() => {
|
97
|
-
if (!
|
98
|
-
|
99
|
-
|
100
|
-
return
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
91
|
+
if (!dataSourceDelegate || !rolesPath) return;
|
92
|
+
if (dataSourceDelegate.initialised !== undefined && !dataSourceDelegate.initialised) return;
|
93
|
+
|
94
|
+
return dataSourceDelegate.listenCollection?.({
|
95
|
+
path: rolesPath,
|
96
|
+
onUpdate(entities: Entity<any>[]): void {
|
97
|
+
setRolesError(undefined);
|
98
|
+
try {
|
99
|
+
const newRoles = entityToRoles(entities);
|
100
|
+
if (!equal(newRoles, roles))
|
106
101
|
setRoles(newRoles);
|
107
|
-
|
108
|
-
console.error("Error loading roles", e);
|
109
|
-
setRolesError(e as Error);
|
110
|
-
}
|
111
|
-
setRolesLoading(false);
|
112
|
-
},
|
113
|
-
error: (e) => {
|
102
|
+
} catch (e) {
|
114
103
|
console.error("Error loading roles", e);
|
115
|
-
setRolesError(e);
|
116
|
-
setRolesLoading(false);
|
104
|
+
setRolesError(e as Error);
|
117
105
|
}
|
106
|
+
setRolesLoading(false);
|
107
|
+
},
|
108
|
+
onError(e: any): void {
|
109
|
+
console.error("Error loading roles", e);
|
110
|
+
setRolesError(e);
|
111
|
+
setRolesLoading(false);
|
118
112
|
}
|
119
|
-
);
|
120
|
-
|
113
|
+
});
|
114
|
+
|
115
|
+
}, [dataSourceDelegate, rolesPath]);
|
121
116
|
|
122
117
|
useEffect(() => {
|
123
|
-
if (!
|
124
|
-
|
125
|
-
|
126
|
-
return
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
118
|
+
if (!dataSourceDelegate || !usersPath) return;
|
119
|
+
if (dataSourceDelegate.initialised !== undefined && !dataSourceDelegate.initialised) return;
|
120
|
+
|
121
|
+
return dataSourceDelegate.listenCollection?.({
|
122
|
+
path: usersPath,
|
123
|
+
onUpdate(entities: Entity<any>[]): void {
|
124
|
+
setUsersError(undefined);
|
125
|
+
try {
|
126
|
+
const newUsers = entitiesToUsers(entities);
|
127
|
+
if (!equal(newUsers, usersWithRoleIds))
|
132
128
|
setUsersWithRoleIds(newUsers);
|
133
|
-
|
134
|
-
console.error("Error loading users", e);
|
135
|
-
setUsersError(e as Error);
|
136
|
-
}
|
137
|
-
setUsersLoading(false);
|
138
|
-
},
|
139
|
-
error: (e) => {
|
129
|
+
} catch (e) {
|
140
130
|
console.error("Error loading users", e);
|
141
|
-
setUsersError(e);
|
142
|
-
setUsersLoading(false);
|
131
|
+
setUsersError(e as Error);
|
143
132
|
}
|
133
|
+
setUsersLoading(false);
|
134
|
+
},
|
135
|
+
onError(e: any): void {
|
136
|
+
console.error("Error loading users", e);
|
137
|
+
setUsersError(e);
|
138
|
+
setUsersLoading(false);
|
144
139
|
}
|
145
|
-
);
|
146
|
-
|
140
|
+
});
|
141
|
+
|
142
|
+
}, [dataSourceDelegate, usersPath]);
|
147
143
|
|
148
144
|
const saveUser = useCallback(async (user: User): Promise<User> => {
|
149
|
-
if (!
|
150
|
-
|
151
|
-
|
145
|
+
if (!dataSourceDelegate) throw Error("useBuildUserManagement Firebase not initialised");
|
146
|
+
if (!usersPath) throw Error("useBuildUserManagement Firestore not initialised");
|
147
|
+
|
152
148
|
console.debug("Persisting user", user);
|
149
|
+
|
153
150
|
const roleIds = user.roles?.map(r => r.id);
|
154
151
|
const {
|
155
152
|
uid,
|
@@ -160,43 +157,64 @@ export function useFirestoreUserManagement({
|
|
160
157
|
roles: roleIds
|
161
158
|
};
|
162
159
|
if (uid) {
|
163
|
-
return
|
160
|
+
return dataSourceDelegate.saveEntity({
|
161
|
+
status: "existing",
|
162
|
+
path: usersPath,
|
163
|
+
entityId: uid,
|
164
|
+
values: data
|
165
|
+
}).then(() => user);
|
164
166
|
} else {
|
165
|
-
return
|
167
|
+
return dataSourceDelegate.saveEntity({
|
168
|
+
status: "new",
|
169
|
+
path: usersPath,
|
170
|
+
values: data
|
171
|
+
}).then(() => user);
|
166
172
|
}
|
167
|
-
}, [usersPath,
|
173
|
+
}, [usersPath, dataSourceDelegate]);
|
168
174
|
|
169
175
|
const saveRole = useCallback((role: Role): Promise<void> => {
|
170
|
-
if (!
|
171
|
-
|
172
|
-
if (!firestore || !rolesPath) throw Error("useFirestoreUserManagement Firestore not initialised");
|
176
|
+
if (!dataSourceDelegate) throw Error("useBuildUserManagement Firebase not initialised");
|
177
|
+
if (!rolesPath) throw Error("useBuildUserManagement Firestore not initialised");
|
173
178
|
console.debug("Persisting role", role);
|
174
179
|
const {
|
175
180
|
id,
|
176
181
|
...roleData
|
177
182
|
} = role;
|
178
|
-
|
179
|
-
|
180
|
-
|
183
|
+
return dataSourceDelegate.saveEntity({
|
184
|
+
status: "existing",
|
185
|
+
path: rolesPath,
|
186
|
+
entityId: id,
|
187
|
+
values: roleData
|
188
|
+
}).then(() => {
|
189
|
+
return;
|
190
|
+
});
|
191
|
+
}, [rolesPath, dataSourceDelegate]);
|
181
192
|
|
182
193
|
const deleteUser = useCallback(async (user: User): Promise<void> => {
|
183
|
-
if (!
|
184
|
-
|
185
|
-
if (!firestore || !usersPath) throw Error("useFirestoreUserManagement Firestore not initialised");
|
194
|
+
if (!dataSourceDelegate) throw Error("useBuildUserManagement Firebase not initialised");
|
195
|
+
if (!usersPath) throw Error("useBuildUserManagement Firestore not initialised");
|
186
196
|
console.debug("Deleting", user);
|
187
197
|
const { uid } = user;
|
188
|
-
|
189
|
-
|
198
|
+
const entity: Entity<any> = {
|
199
|
+
path: usersPath,
|
200
|
+
id: uid,
|
201
|
+
values: {}
|
202
|
+
};
|
203
|
+
await dataSourceDelegate.deleteEntity({ entity })
|
204
|
+
}, [usersPath, dataSourceDelegate]);
|
190
205
|
|
191
|
-
const deleteRole = useCallback((role: Role): Promise<void> => {
|
192
|
-
if (!
|
193
|
-
|
194
|
-
if (!firestore || !rolesPath) throw Error("useFirestoreUserManagement Firestore not initialised");
|
206
|
+
const deleteRole = useCallback(async (role: Role): Promise<void> => {
|
207
|
+
if (!dataSourceDelegate) throw Error("useBuildUserManagement Firebase not initialised");
|
208
|
+
if (!rolesPath) throw Error("useBuildUserManagement Firestore not initialised");
|
195
209
|
console.debug("Deleting", role);
|
196
210
|
const { id } = role;
|
197
|
-
const
|
198
|
-
|
199
|
-
|
211
|
+
const entity: Entity<any> = {
|
212
|
+
path: usersPath,
|
213
|
+
id: id,
|
214
|
+
values: {}
|
215
|
+
};
|
216
|
+
await dataSourceDelegate.deleteEntity({ entity })
|
217
|
+
}, [rolesPath, dataSourceDelegate]);
|
200
218
|
|
201
219
|
const collectionPermissions: PermissionsBuilder = useCallback(({
|
202
220
|
collection,
|
@@ -256,22 +274,22 @@ export function useFirestoreUserManagement({
|
|
256
274
|
}
|
257
275
|
}
|
258
276
|
|
259
|
-
const
|
277
|
+
const entitiesToUsers = (docs: Entity<Omit<UserWithRoleIds, "id">>[]): (UserWithRoleIds)[] => {
|
260
278
|
return docs.map((doc) => {
|
261
|
-
const data = doc.
|
279
|
+
const data = doc.values as any;
|
262
280
|
const newVar = {
|
263
281
|
uid: doc.id,
|
264
282
|
...data,
|
265
|
-
created_on: data?.created_on
|
266
|
-
updated_on: data?.updated_on
|
283
|
+
created_on: data?.created_on,
|
284
|
+
updated_on: data?.updated_on
|
267
285
|
};
|
268
286
|
return newVar as (UserWithRoleIds);
|
269
287
|
});
|
270
288
|
}
|
271
289
|
|
272
|
-
const
|
273
|
-
return
|
290
|
+
const entityToRoles = (entities: Entity<Omit<Role, "id">>[]): Role[] => {
|
291
|
+
return entities.map((doc) => ({
|
274
292
|
id: doc.id,
|
275
|
-
...doc.
|
293
|
+
...doc.values
|
276
294
|
} as Role));
|
277
295
|
}
|