@firecms/user_management 3.0.0-beta.8 → 3.0.0-canary.100
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 +3 -2
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/{useFirestoreUserManagement.d.ts → useBuildUserManagement.d.ts} +8 -7
- package/dist/index.es.js +994 -784
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1561 -1
- 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} +119 -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,69 @@ 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
|
-
|
109
|
-
setRolesError(e as Error);
|
110
|
-
}
|
111
|
-
setRolesLoading(false);
|
112
|
-
},
|
113
|
-
error: (e) => {
|
102
|
+
} catch (e) {
|
103
|
+
setRoles([]);
|
114
104
|
console.error("Error loading roles", e);
|
115
|
-
setRolesError(e);
|
116
|
-
setRolesLoading(false);
|
105
|
+
setRolesError(e as Error);
|
117
106
|
}
|
107
|
+
setRolesLoading(false);
|
108
|
+
},
|
109
|
+
onError(e: any): void {
|
110
|
+
setRoles([]);
|
111
|
+
console.error("Error loading roles", e);
|
112
|
+
setRolesError(e);
|
113
|
+
setRolesLoading(false);
|
118
114
|
}
|
119
|
-
);
|
120
|
-
|
115
|
+
});
|
116
|
+
|
117
|
+
}, [dataSourceDelegate?.initialised, rolesPath]);
|
121
118
|
|
122
119
|
useEffect(() => {
|
123
|
-
if (!
|
124
|
-
|
125
|
-
|
126
|
-
return
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
120
|
+
if (!dataSourceDelegate || !usersPath) return;
|
121
|
+
if (dataSourceDelegate.initialised !== undefined && !dataSourceDelegate.initialised) return;
|
122
|
+
|
123
|
+
return dataSourceDelegate.listenCollection?.({
|
124
|
+
path: usersPath,
|
125
|
+
onUpdate(entities: Entity<any>[]): void {
|
126
|
+
setUsersError(undefined);
|
127
|
+
try {
|
128
|
+
const newUsers = entitiesToUsers(entities);
|
129
|
+
if (!equal(newUsers, usersWithRoleIds))
|
132
130
|
setUsersWithRoleIds(newUsers);
|
133
|
-
|
134
|
-
|
135
|
-
setUsersError(e as Error);
|
136
|
-
}
|
137
|
-
setUsersLoading(false);
|
138
|
-
},
|
139
|
-
error: (e) => {
|
131
|
+
} catch (e) {
|
132
|
+
setUsersWithRoleIds([]);
|
140
133
|
console.error("Error loading users", e);
|
141
|
-
setUsersError(e);
|
142
|
-
setUsersLoading(false);
|
134
|
+
setUsersError(e as Error);
|
143
135
|
}
|
136
|
+
setUsersLoading(false);
|
137
|
+
},
|
138
|
+
onError(e: any): void {
|
139
|
+
setUsersWithRoleIds([]);
|
140
|
+
console.error("Error loading users", e);
|
141
|
+
setUsersError(e);
|
142
|
+
setUsersLoading(false);
|
144
143
|
}
|
145
|
-
);
|
146
|
-
|
144
|
+
});
|
145
|
+
|
146
|
+
}, [dataSourceDelegate?.initialised, usersPath]);
|
147
147
|
|
148
148
|
const saveUser = useCallback(async (user: User): Promise<User> => {
|
149
|
-
if (!
|
150
|
-
|
151
|
-
|
149
|
+
if (!dataSourceDelegate) throw Error("useBuildUserManagement Firebase not initialised");
|
150
|
+
if (!usersPath) throw Error("useBuildUserManagement Firestore not initialised");
|
151
|
+
|
152
152
|
console.debug("Persisting user", user);
|
153
|
+
|
153
154
|
const roleIds = user.roles?.map(r => r.id);
|
154
155
|
const {
|
155
156
|
uid,
|
@@ -160,43 +161,64 @@ export function useFirestoreUserManagement({
|
|
160
161
|
roles: roleIds
|
161
162
|
};
|
162
163
|
if (uid) {
|
163
|
-
return
|
164
|
+
return dataSourceDelegate.saveEntity({
|
165
|
+
status: "existing",
|
166
|
+
path: usersPath,
|
167
|
+
entityId: uid,
|
168
|
+
values: data
|
169
|
+
}).then(() => user);
|
164
170
|
} else {
|
165
|
-
return
|
171
|
+
return dataSourceDelegate.saveEntity({
|
172
|
+
status: "new",
|
173
|
+
path: usersPath,
|
174
|
+
values: data
|
175
|
+
}).then(() => user);
|
166
176
|
}
|
167
|
-
}, [usersPath,
|
177
|
+
}, [usersPath, dataSourceDelegate?.initialised]);
|
168
178
|
|
169
179
|
const saveRole = useCallback((role: Role): Promise<void> => {
|
170
|
-
if (!
|
171
|
-
|
172
|
-
if (!firestore || !rolesPath) throw Error("useFirestoreUserManagement Firestore not initialised");
|
180
|
+
if (!dataSourceDelegate) throw Error("useBuildUserManagement Firebase not initialised");
|
181
|
+
if (!rolesPath) throw Error("useBuildUserManagement Firestore not initialised");
|
173
182
|
console.debug("Persisting role", role);
|
174
183
|
const {
|
175
184
|
id,
|
176
185
|
...roleData
|
177
186
|
} = role;
|
178
|
-
|
179
|
-
|
180
|
-
|
187
|
+
return dataSourceDelegate.saveEntity({
|
188
|
+
status: "existing",
|
189
|
+
path: rolesPath,
|
190
|
+
entityId: id,
|
191
|
+
values: roleData
|
192
|
+
}).then(() => {
|
193
|
+
return;
|
194
|
+
});
|
195
|
+
}, [rolesPath, dataSourceDelegate?.initialised]);
|
181
196
|
|
182
197
|
const deleteUser = useCallback(async (user: User): Promise<void> => {
|
183
|
-
if (!
|
184
|
-
|
185
|
-
if (!firestore || !usersPath) throw Error("useFirestoreUserManagement Firestore not initialised");
|
198
|
+
if (!dataSourceDelegate) throw Error("useBuildUserManagement Firebase not initialised");
|
199
|
+
if (!usersPath) throw Error("useBuildUserManagement Firestore not initialised");
|
186
200
|
console.debug("Deleting", user);
|
187
201
|
const { uid } = user;
|
188
|
-
|
189
|
-
|
202
|
+
const entity: Entity<any> = {
|
203
|
+
path: usersPath,
|
204
|
+
id: uid,
|
205
|
+
values: {}
|
206
|
+
};
|
207
|
+
await dataSourceDelegate.deleteEntity({ entity })
|
208
|
+
}, [usersPath, dataSourceDelegate?.initialised]);
|
190
209
|
|
191
|
-
const deleteRole = useCallback((role: Role): Promise<void> => {
|
192
|
-
if (!
|
193
|
-
|
194
|
-
if (!firestore || !rolesPath) throw Error("useFirestoreUserManagement Firestore not initialised");
|
210
|
+
const deleteRole = useCallback(async (role: Role): Promise<void> => {
|
211
|
+
if (!dataSourceDelegate) throw Error("useBuildUserManagement Firebase not initialised");
|
212
|
+
if (!rolesPath) throw Error("useBuildUserManagement Firestore not initialised");
|
195
213
|
console.debug("Deleting", role);
|
196
214
|
const { id } = role;
|
197
|
-
const
|
198
|
-
|
199
|
-
|
215
|
+
const entity: Entity<any> = {
|
216
|
+
path: usersPath,
|
217
|
+
id: id,
|
218
|
+
values: {}
|
219
|
+
};
|
220
|
+
await dataSourceDelegate.deleteEntity({ entity })
|
221
|
+
}, [rolesPath, dataSourceDelegate?.initialised]);
|
200
222
|
|
201
223
|
const collectionPermissions: PermissionsBuilder = useCallback(({
|
202
224
|
collection,
|
@@ -256,22 +278,22 @@ export function useFirestoreUserManagement({
|
|
256
278
|
}
|
257
279
|
}
|
258
280
|
|
259
|
-
const
|
281
|
+
const entitiesToUsers = (docs: Entity<Omit<UserWithRoleIds, "id">>[]): (UserWithRoleIds)[] => {
|
260
282
|
return docs.map((doc) => {
|
261
|
-
const data = doc.
|
283
|
+
const data = doc.values as any;
|
262
284
|
const newVar = {
|
263
285
|
uid: doc.id,
|
264
286
|
...data,
|
265
|
-
created_on: data?.created_on
|
266
|
-
updated_on: data?.updated_on
|
287
|
+
created_on: data?.created_on,
|
288
|
+
updated_on: data?.updated_on
|
267
289
|
};
|
268
290
|
return newVar as (UserWithRoleIds);
|
269
291
|
});
|
270
292
|
}
|
271
293
|
|
272
|
-
const
|
273
|
-
return
|
294
|
+
const entityToRoles = (entities: Entity<Omit<Role, "id">>[]): Role[] => {
|
295
|
+
return entities.map((doc) => ({
|
274
296
|
id: doc.id,
|
275
|
-
...doc.
|
297
|
+
...doc.values
|
276
298
|
} as Role));
|
277
299
|
}
|