@abpjs/identity-pro 0.7.2
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 +165 -0
- package/README.md +402 -0
- package/dist/index.d.mts +805 -0
- package/dist/index.d.ts +805 -0
- package/dist/index.js +1910 -0
- package/dist/index.mjs +1909 -0
- package/package.json +90 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1909 @@
|
|
|
1
|
+
// src/models/identity.ts
|
|
2
|
+
var Identity;
|
|
3
|
+
((Identity2) => {
|
|
4
|
+
let ClaimValueType;
|
|
5
|
+
((ClaimValueType2) => {
|
|
6
|
+
ClaimValueType2[ClaimValueType2["String"] = 0] = "String";
|
|
7
|
+
ClaimValueType2[ClaimValueType2["Int"] = 1] = "Int";
|
|
8
|
+
ClaimValueType2[ClaimValueType2["Boolean"] = 2] = "Boolean";
|
|
9
|
+
ClaimValueType2[ClaimValueType2["DateTime"] = 3] = "DateTime";
|
|
10
|
+
})(ClaimValueType = Identity2.ClaimValueType || (Identity2.ClaimValueType = {}));
|
|
11
|
+
})(Identity || (Identity = {}));
|
|
12
|
+
|
|
13
|
+
// src/services/identity.service.ts
|
|
14
|
+
var IdentityService = class {
|
|
15
|
+
constructor(rest) {
|
|
16
|
+
this.rest = rest;
|
|
17
|
+
}
|
|
18
|
+
// ========================
|
|
19
|
+
// Role Operations
|
|
20
|
+
// ========================
|
|
21
|
+
/**
|
|
22
|
+
* Get all roles with optional pagination/filtering (v0.9.0)
|
|
23
|
+
* @param params - Optional query parameters for pagination and filtering
|
|
24
|
+
* @returns Promise with paginated role response
|
|
25
|
+
*/
|
|
26
|
+
getRoles(params = {}) {
|
|
27
|
+
return this.rest.request({
|
|
28
|
+
method: "GET",
|
|
29
|
+
url: "/api/identity/roles",
|
|
30
|
+
params
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get a role by ID
|
|
35
|
+
* @param id - The role ID
|
|
36
|
+
* @returns Promise with the role item
|
|
37
|
+
*/
|
|
38
|
+
getRoleById(id) {
|
|
39
|
+
return this.rest.request({
|
|
40
|
+
method: "GET",
|
|
41
|
+
url: `/api/identity/roles/${id}`
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Delete a role
|
|
46
|
+
* @param id - The role ID to delete
|
|
47
|
+
* @returns Promise with the deleted role
|
|
48
|
+
*/
|
|
49
|
+
deleteRole(id) {
|
|
50
|
+
return this.rest.request({
|
|
51
|
+
method: "DELETE",
|
|
52
|
+
url: `/api/identity/roles/${id}`
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Create a new role
|
|
57
|
+
* @param body - The role data to create
|
|
58
|
+
* @returns Promise with the created role
|
|
59
|
+
*/
|
|
60
|
+
createRole(body) {
|
|
61
|
+
return this.rest.request({
|
|
62
|
+
method: "POST",
|
|
63
|
+
url: "/api/identity/roles",
|
|
64
|
+
body
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Update an existing role
|
|
69
|
+
* @param id - The role ID to update
|
|
70
|
+
* @param body - The updated role data
|
|
71
|
+
* @returns Promise with the updated role
|
|
72
|
+
*/
|
|
73
|
+
updateRole(id, body) {
|
|
74
|
+
return this.rest.request({
|
|
75
|
+
method: "PUT",
|
|
76
|
+
url: `/api/identity/roles/${id}`,
|
|
77
|
+
body
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// ========================
|
|
81
|
+
// User Operations
|
|
82
|
+
// ========================
|
|
83
|
+
/**
|
|
84
|
+
* Get users with pagination and filtering
|
|
85
|
+
* @param params - Query parameters for pagination and filtering
|
|
86
|
+
* @returns Promise with paginated user response
|
|
87
|
+
*/
|
|
88
|
+
getUsers(params = {}) {
|
|
89
|
+
return this.rest.request({
|
|
90
|
+
method: "GET",
|
|
91
|
+
url: "/api/identity/users",
|
|
92
|
+
params
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get a user by ID
|
|
97
|
+
* @param id - The user ID
|
|
98
|
+
* @returns Promise with the user item
|
|
99
|
+
*/
|
|
100
|
+
getUserById(id) {
|
|
101
|
+
return this.rest.request({
|
|
102
|
+
method: "GET",
|
|
103
|
+
url: `/api/identity/users/${id}`
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get roles assigned to a user
|
|
108
|
+
* @param id - The user ID
|
|
109
|
+
* @returns Promise with the user's roles
|
|
110
|
+
*/
|
|
111
|
+
getUserRoles(id) {
|
|
112
|
+
return this.rest.request({
|
|
113
|
+
method: "GET",
|
|
114
|
+
url: `/api/identity/users/${id}/roles`
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Delete a user
|
|
119
|
+
* @param id - The user ID to delete
|
|
120
|
+
* @returns Promise resolving when complete
|
|
121
|
+
*/
|
|
122
|
+
deleteUser(id) {
|
|
123
|
+
return this.rest.request({
|
|
124
|
+
method: "DELETE",
|
|
125
|
+
url: `/api/identity/users/${id}`
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Create a new user
|
|
130
|
+
* @param body - The user data to create
|
|
131
|
+
* @returns Promise with the created user
|
|
132
|
+
*/
|
|
133
|
+
createUser(body) {
|
|
134
|
+
return this.rest.request({
|
|
135
|
+
method: "POST",
|
|
136
|
+
url: "/api/identity/users",
|
|
137
|
+
body
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Update an existing user
|
|
142
|
+
* @param id - The user ID to update
|
|
143
|
+
* @param body - The updated user data
|
|
144
|
+
* @returns Promise with the updated user
|
|
145
|
+
*/
|
|
146
|
+
updateUser(id, body) {
|
|
147
|
+
return this.rest.request({
|
|
148
|
+
method: "PUT",
|
|
149
|
+
url: `/api/identity/users/${id}`,
|
|
150
|
+
body
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// ========================
|
|
154
|
+
// Pro: Claim Type Operations
|
|
155
|
+
// ========================
|
|
156
|
+
/**
|
|
157
|
+
* Get all claim type names for dropdowns
|
|
158
|
+
* Pro feature since 0.7.2
|
|
159
|
+
* @returns Promise with claim type names
|
|
160
|
+
*/
|
|
161
|
+
getClaimTypeNames() {
|
|
162
|
+
return this.rest.request({
|
|
163
|
+
method: "GET",
|
|
164
|
+
url: "/api/identity/claim-types/all"
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get claim types with pagination
|
|
169
|
+
* Pro feature since 0.7.2
|
|
170
|
+
* @param params - Query parameters for pagination and filtering
|
|
171
|
+
* @returns Promise with paginated claim types response
|
|
172
|
+
*/
|
|
173
|
+
getClaimTypes(params = {}) {
|
|
174
|
+
return this.rest.request({
|
|
175
|
+
method: "GET",
|
|
176
|
+
url: "/api/identity/claim-types",
|
|
177
|
+
params
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get a claim type by ID
|
|
182
|
+
* Pro feature since 0.7.2
|
|
183
|
+
* @param id - The claim type ID
|
|
184
|
+
* @returns Promise with the claim type
|
|
185
|
+
*/
|
|
186
|
+
getClaimTypeById(id) {
|
|
187
|
+
return this.rest.request({
|
|
188
|
+
method: "GET",
|
|
189
|
+
url: `/api/identity/claim-types/${id}`
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Create a new claim type
|
|
194
|
+
* Pro feature since 0.7.2
|
|
195
|
+
* @param body - The claim type data
|
|
196
|
+
* @returns Promise with the created claim type
|
|
197
|
+
*/
|
|
198
|
+
createClaimType(body) {
|
|
199
|
+
return this.rest.request({
|
|
200
|
+
method: "POST",
|
|
201
|
+
url: "/api/identity/claim-types",
|
|
202
|
+
body
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Update an existing claim type
|
|
207
|
+
* Pro feature since 0.7.2
|
|
208
|
+
* @param body - The claim type data (must include id)
|
|
209
|
+
* @returns Promise with the updated claim type
|
|
210
|
+
*/
|
|
211
|
+
updateClaimType(body) {
|
|
212
|
+
return this.rest.request({
|
|
213
|
+
method: "PUT",
|
|
214
|
+
url: `/api/identity/claim-types/${body.id}`,
|
|
215
|
+
body
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Delete a claim type
|
|
220
|
+
* Pro feature since 0.7.2
|
|
221
|
+
* @param id - The claim type ID to delete
|
|
222
|
+
* @returns Promise resolving when complete
|
|
223
|
+
*/
|
|
224
|
+
deleteClaimType(id) {
|
|
225
|
+
return this.rest.request({
|
|
226
|
+
method: "DELETE",
|
|
227
|
+
url: `/api/identity/claim-types/${id}`
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
// ========================
|
|
231
|
+
// Pro: User/Role Claims
|
|
232
|
+
// ========================
|
|
233
|
+
/**
|
|
234
|
+
* Get claims for a user or role
|
|
235
|
+
* Pro feature since 0.7.2
|
|
236
|
+
* @param body - Object with id and type ('users' | 'roles')
|
|
237
|
+
* @returns Promise with claim requests
|
|
238
|
+
*/
|
|
239
|
+
getClaims(body) {
|
|
240
|
+
return this.rest.request({
|
|
241
|
+
method: "GET",
|
|
242
|
+
url: `/api/identity/${body.type}/${body.id}/claims`
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Update claims for a user or role
|
|
247
|
+
* Pro feature since 0.7.2
|
|
248
|
+
* @param body - Object with id, type, and claims array
|
|
249
|
+
* @returns Promise resolving when complete
|
|
250
|
+
*/
|
|
251
|
+
updateClaims(body) {
|
|
252
|
+
return this.rest.request({
|
|
253
|
+
method: "PUT",
|
|
254
|
+
url: `/api/identity/${body.type}/${body.id}/claims`,
|
|
255
|
+
body: body.claims
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// src/hooks/useRoles.ts
|
|
261
|
+
import { useState, useCallback, useMemo } from "react";
|
|
262
|
+
import { useRestService } from "@abpjs/core";
|
|
263
|
+
function useRoles() {
|
|
264
|
+
const restService = useRestService();
|
|
265
|
+
const service = useMemo(() => new IdentityService(restService), [restService]);
|
|
266
|
+
const [roles, setRoles] = useState([]);
|
|
267
|
+
const [totalCount, setTotalCount] = useState(0);
|
|
268
|
+
const [selectedRole, setSelectedRole] = useState(null);
|
|
269
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
270
|
+
const [error, setError] = useState(null);
|
|
271
|
+
const [sortKey, setSortKey] = useState("name");
|
|
272
|
+
const [sortOrder, setSortOrder] = useState("");
|
|
273
|
+
const fetchRoles = useCallback(async (params) => {
|
|
274
|
+
setIsLoading(true);
|
|
275
|
+
setError(null);
|
|
276
|
+
try {
|
|
277
|
+
const response = await service.getRoles(params);
|
|
278
|
+
setRoles(response.items || []);
|
|
279
|
+
setTotalCount(response.totalCount || 0);
|
|
280
|
+
setIsLoading(false);
|
|
281
|
+
return { success: true };
|
|
282
|
+
} catch (err) {
|
|
283
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch roles";
|
|
284
|
+
setError(errorMessage);
|
|
285
|
+
setIsLoading(false);
|
|
286
|
+
return { success: false, error: errorMessage };
|
|
287
|
+
}
|
|
288
|
+
}, [service]);
|
|
289
|
+
const getRoleById = useCallback(
|
|
290
|
+
async (id) => {
|
|
291
|
+
setIsLoading(true);
|
|
292
|
+
setError(null);
|
|
293
|
+
try {
|
|
294
|
+
const role = await service.getRoleById(id);
|
|
295
|
+
setSelectedRole(role);
|
|
296
|
+
setIsLoading(false);
|
|
297
|
+
return { success: true };
|
|
298
|
+
} catch (err) {
|
|
299
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch role";
|
|
300
|
+
setError(errorMessage);
|
|
301
|
+
setIsLoading(false);
|
|
302
|
+
return { success: false, error: errorMessage };
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
[service]
|
|
306
|
+
);
|
|
307
|
+
const createRole = useCallback(
|
|
308
|
+
async (role) => {
|
|
309
|
+
setIsLoading(true);
|
|
310
|
+
setError(null);
|
|
311
|
+
try {
|
|
312
|
+
await service.createRole(role);
|
|
313
|
+
await fetchRoles();
|
|
314
|
+
return { success: true };
|
|
315
|
+
} catch (err) {
|
|
316
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to create role";
|
|
317
|
+
setError(errorMessage);
|
|
318
|
+
setIsLoading(false);
|
|
319
|
+
return { success: false, error: errorMessage };
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
[service, fetchRoles]
|
|
323
|
+
);
|
|
324
|
+
const updateRole = useCallback(
|
|
325
|
+
async (id, role) => {
|
|
326
|
+
setIsLoading(true);
|
|
327
|
+
setError(null);
|
|
328
|
+
try {
|
|
329
|
+
await service.updateRole(id, role);
|
|
330
|
+
await fetchRoles();
|
|
331
|
+
return { success: true };
|
|
332
|
+
} catch (err) {
|
|
333
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to update role";
|
|
334
|
+
setError(errorMessage);
|
|
335
|
+
setIsLoading(false);
|
|
336
|
+
return { success: false, error: errorMessage };
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
[service, fetchRoles]
|
|
340
|
+
);
|
|
341
|
+
const deleteRole = useCallback(
|
|
342
|
+
async (id) => {
|
|
343
|
+
setIsLoading(true);
|
|
344
|
+
setError(null);
|
|
345
|
+
try {
|
|
346
|
+
await service.deleteRole(id);
|
|
347
|
+
await fetchRoles();
|
|
348
|
+
return { success: true };
|
|
349
|
+
} catch (err) {
|
|
350
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to delete role";
|
|
351
|
+
setError(errorMessage);
|
|
352
|
+
setIsLoading(false);
|
|
353
|
+
return { success: false, error: errorMessage };
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
[service, fetchRoles]
|
|
357
|
+
);
|
|
358
|
+
const reset = useCallback(() => {
|
|
359
|
+
setRoles([]);
|
|
360
|
+
setTotalCount(0);
|
|
361
|
+
setSelectedRole(null);
|
|
362
|
+
setIsLoading(false);
|
|
363
|
+
setError(null);
|
|
364
|
+
}, []);
|
|
365
|
+
return {
|
|
366
|
+
roles,
|
|
367
|
+
totalCount,
|
|
368
|
+
selectedRole,
|
|
369
|
+
isLoading,
|
|
370
|
+
error,
|
|
371
|
+
sortKey,
|
|
372
|
+
sortOrder,
|
|
373
|
+
fetchRoles,
|
|
374
|
+
getRoleById,
|
|
375
|
+
createRole,
|
|
376
|
+
updateRole,
|
|
377
|
+
deleteRole,
|
|
378
|
+
setSelectedRole,
|
|
379
|
+
setSortKey,
|
|
380
|
+
setSortOrder,
|
|
381
|
+
reset
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// src/hooks/useUsers.ts
|
|
386
|
+
import { useState as useState2, useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
387
|
+
import { useRestService as useRestService2 } from "@abpjs/core";
|
|
388
|
+
var DEFAULT_PAGE_QUERY = {
|
|
389
|
+
sorting: "userName",
|
|
390
|
+
skipCount: 0,
|
|
391
|
+
maxResultCount: 10
|
|
392
|
+
};
|
|
393
|
+
function useUsers() {
|
|
394
|
+
const restService = useRestService2();
|
|
395
|
+
const service = useMemo2(() => new IdentityService(restService), [restService]);
|
|
396
|
+
const [users, setUsers] = useState2([]);
|
|
397
|
+
const [totalCount, setTotalCount] = useState2(0);
|
|
398
|
+
const [selectedUser, setSelectedUser] = useState2(null);
|
|
399
|
+
const [selectedUserRoles, setSelectedUserRoles] = useState2([]);
|
|
400
|
+
const [isLoading, setIsLoading] = useState2(false);
|
|
401
|
+
const [error, setError] = useState2(null);
|
|
402
|
+
const [pageQuery, setPageQuery] = useState2(DEFAULT_PAGE_QUERY);
|
|
403
|
+
const [sortKey, setSortKey] = useState2("userName");
|
|
404
|
+
const [sortOrder, setSortOrder] = useState2("");
|
|
405
|
+
const fetchUsers = useCallback2(
|
|
406
|
+
async (params) => {
|
|
407
|
+
setIsLoading(true);
|
|
408
|
+
setError(null);
|
|
409
|
+
const queryParams = params || pageQuery;
|
|
410
|
+
try {
|
|
411
|
+
const response = await service.getUsers(queryParams);
|
|
412
|
+
setUsers(response.items || []);
|
|
413
|
+
setTotalCount(response.totalCount || 0);
|
|
414
|
+
setIsLoading(false);
|
|
415
|
+
return { success: true };
|
|
416
|
+
} catch (err) {
|
|
417
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch users";
|
|
418
|
+
setError(errorMessage);
|
|
419
|
+
setIsLoading(false);
|
|
420
|
+
return { success: false, error: errorMessage };
|
|
421
|
+
}
|
|
422
|
+
},
|
|
423
|
+
[service, pageQuery]
|
|
424
|
+
);
|
|
425
|
+
const getUserById = useCallback2(
|
|
426
|
+
async (id) => {
|
|
427
|
+
setIsLoading(true);
|
|
428
|
+
setError(null);
|
|
429
|
+
try {
|
|
430
|
+
const user = await service.getUserById(id);
|
|
431
|
+
setSelectedUser(user);
|
|
432
|
+
setIsLoading(false);
|
|
433
|
+
return { success: true };
|
|
434
|
+
} catch (err) {
|
|
435
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch user";
|
|
436
|
+
setError(errorMessage);
|
|
437
|
+
setIsLoading(false);
|
|
438
|
+
return { success: false, error: errorMessage };
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
[service]
|
|
442
|
+
);
|
|
443
|
+
const getUserRoles = useCallback2(
|
|
444
|
+
async (id) => {
|
|
445
|
+
setIsLoading(true);
|
|
446
|
+
setError(null);
|
|
447
|
+
try {
|
|
448
|
+
const response = await service.getUserRoles(id);
|
|
449
|
+
setSelectedUserRoles(response.items || []);
|
|
450
|
+
setIsLoading(false);
|
|
451
|
+
return { success: true };
|
|
452
|
+
} catch (err) {
|
|
453
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch user roles";
|
|
454
|
+
setError(errorMessage);
|
|
455
|
+
setIsLoading(false);
|
|
456
|
+
return { success: false, error: errorMessage };
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
[service]
|
|
460
|
+
);
|
|
461
|
+
const createUser = useCallback2(
|
|
462
|
+
async (user) => {
|
|
463
|
+
setIsLoading(true);
|
|
464
|
+
setError(null);
|
|
465
|
+
try {
|
|
466
|
+
await service.createUser(user);
|
|
467
|
+
await fetchUsers();
|
|
468
|
+
return { success: true };
|
|
469
|
+
} catch (err) {
|
|
470
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to create user";
|
|
471
|
+
setError(errorMessage);
|
|
472
|
+
setIsLoading(false);
|
|
473
|
+
return { success: false, error: errorMessage };
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
[service, fetchUsers]
|
|
477
|
+
);
|
|
478
|
+
const updateUser = useCallback2(
|
|
479
|
+
async (id, user) => {
|
|
480
|
+
setIsLoading(true);
|
|
481
|
+
setError(null);
|
|
482
|
+
try {
|
|
483
|
+
await service.updateUser(id, user);
|
|
484
|
+
await fetchUsers();
|
|
485
|
+
return { success: true };
|
|
486
|
+
} catch (err) {
|
|
487
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to update user";
|
|
488
|
+
setError(errorMessage);
|
|
489
|
+
setIsLoading(false);
|
|
490
|
+
return { success: false, error: errorMessage };
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
[service, fetchUsers]
|
|
494
|
+
);
|
|
495
|
+
const deleteUser = useCallback2(
|
|
496
|
+
async (id) => {
|
|
497
|
+
setIsLoading(true);
|
|
498
|
+
setError(null);
|
|
499
|
+
try {
|
|
500
|
+
await service.deleteUser(id);
|
|
501
|
+
await fetchUsers();
|
|
502
|
+
return { success: true };
|
|
503
|
+
} catch (err) {
|
|
504
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to delete user";
|
|
505
|
+
setError(errorMessage);
|
|
506
|
+
setIsLoading(false);
|
|
507
|
+
return { success: false, error: errorMessage };
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
[service, fetchUsers]
|
|
511
|
+
);
|
|
512
|
+
const reset = useCallback2(() => {
|
|
513
|
+
setUsers([]);
|
|
514
|
+
setTotalCount(0);
|
|
515
|
+
setSelectedUser(null);
|
|
516
|
+
setSelectedUserRoles([]);
|
|
517
|
+
setIsLoading(false);
|
|
518
|
+
setError(null);
|
|
519
|
+
setPageQuery(DEFAULT_PAGE_QUERY);
|
|
520
|
+
}, []);
|
|
521
|
+
return {
|
|
522
|
+
users,
|
|
523
|
+
totalCount,
|
|
524
|
+
selectedUser,
|
|
525
|
+
selectedUserRoles,
|
|
526
|
+
isLoading,
|
|
527
|
+
error,
|
|
528
|
+
pageQuery,
|
|
529
|
+
sortKey,
|
|
530
|
+
sortOrder,
|
|
531
|
+
fetchUsers,
|
|
532
|
+
getUserById,
|
|
533
|
+
getUserRoles,
|
|
534
|
+
createUser,
|
|
535
|
+
updateUser,
|
|
536
|
+
deleteUser,
|
|
537
|
+
setSelectedUser,
|
|
538
|
+
setPageQuery,
|
|
539
|
+
setSortKey,
|
|
540
|
+
setSortOrder,
|
|
541
|
+
reset
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// src/hooks/useIdentity.ts
|
|
546
|
+
import { useCallback as useCallback3, useMemo as useMemo3 } from "react";
|
|
547
|
+
function useIdentity() {
|
|
548
|
+
const rolesHook = useRoles();
|
|
549
|
+
const usersHook = useUsers();
|
|
550
|
+
const isLoading = useMemo3(
|
|
551
|
+
() => rolesHook.isLoading || usersHook.isLoading,
|
|
552
|
+
[rolesHook.isLoading, usersHook.isLoading]
|
|
553
|
+
);
|
|
554
|
+
const error = useMemo3(
|
|
555
|
+
() => rolesHook.error || usersHook.error,
|
|
556
|
+
[rolesHook.error, usersHook.error]
|
|
557
|
+
);
|
|
558
|
+
const resetAll = useCallback3(() => {
|
|
559
|
+
rolesHook.reset();
|
|
560
|
+
usersHook.reset();
|
|
561
|
+
}, [rolesHook, usersHook]);
|
|
562
|
+
return {
|
|
563
|
+
roles: rolesHook,
|
|
564
|
+
users: usersHook,
|
|
565
|
+
isLoading,
|
|
566
|
+
error,
|
|
567
|
+
resetAll
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// src/hooks/useClaims.ts
|
|
572
|
+
import { useState as useState3, useCallback as useCallback4, useMemo as useMemo4 } from "react";
|
|
573
|
+
import { useRestService as useRestService3 } from "@abpjs/core";
|
|
574
|
+
function useClaims() {
|
|
575
|
+
const restService = useRestService3();
|
|
576
|
+
const service = useMemo4(() => new IdentityService(restService), [restService]);
|
|
577
|
+
const [claimTypes, setClaimTypes] = useState3([]);
|
|
578
|
+
const [totalCount, setTotalCount] = useState3(0);
|
|
579
|
+
const [claimTypeNames, setClaimTypeNames] = useState3([]);
|
|
580
|
+
const [selectedClaimType, setSelectedClaimType] = useState3(null);
|
|
581
|
+
const [isLoading, setIsLoading] = useState3(false);
|
|
582
|
+
const [error, setError] = useState3(null);
|
|
583
|
+
const [sortKey, setSortKey] = useState3("name");
|
|
584
|
+
const [sortOrder, setSortOrder] = useState3("");
|
|
585
|
+
const fetchClaimTypes = useCallback4(async (params) => {
|
|
586
|
+
setIsLoading(true);
|
|
587
|
+
setError(null);
|
|
588
|
+
try {
|
|
589
|
+
const response = await service.getClaimTypes(params);
|
|
590
|
+
setClaimTypes(response.items || []);
|
|
591
|
+
setTotalCount(response.totalCount || 0);
|
|
592
|
+
setIsLoading(false);
|
|
593
|
+
return { success: true };
|
|
594
|
+
} catch (err) {
|
|
595
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch claim types";
|
|
596
|
+
setError(errorMessage);
|
|
597
|
+
setIsLoading(false);
|
|
598
|
+
return { success: false, error: errorMessage };
|
|
599
|
+
}
|
|
600
|
+
}, [service]);
|
|
601
|
+
const fetchClaimTypeNames = useCallback4(async () => {
|
|
602
|
+
setIsLoading(true);
|
|
603
|
+
setError(null);
|
|
604
|
+
try {
|
|
605
|
+
const response = await service.getClaimTypeNames();
|
|
606
|
+
setClaimTypeNames(response || []);
|
|
607
|
+
setIsLoading(false);
|
|
608
|
+
return { success: true };
|
|
609
|
+
} catch (err) {
|
|
610
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch claim type names";
|
|
611
|
+
setError(errorMessage);
|
|
612
|
+
setIsLoading(false);
|
|
613
|
+
return { success: false, error: errorMessage };
|
|
614
|
+
}
|
|
615
|
+
}, [service]);
|
|
616
|
+
const getClaimTypeById = useCallback4(
|
|
617
|
+
async (id) => {
|
|
618
|
+
setIsLoading(true);
|
|
619
|
+
setError(null);
|
|
620
|
+
try {
|
|
621
|
+
const claimType = await service.getClaimTypeById(id);
|
|
622
|
+
setSelectedClaimType(claimType);
|
|
623
|
+
setIsLoading(false);
|
|
624
|
+
return { success: true };
|
|
625
|
+
} catch (err) {
|
|
626
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch claim type";
|
|
627
|
+
setError(errorMessage);
|
|
628
|
+
setIsLoading(false);
|
|
629
|
+
return { success: false, error: errorMessage };
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
[service]
|
|
633
|
+
);
|
|
634
|
+
const createClaimType = useCallback4(
|
|
635
|
+
async (claimType) => {
|
|
636
|
+
setIsLoading(true);
|
|
637
|
+
setError(null);
|
|
638
|
+
try {
|
|
639
|
+
await service.createClaimType(claimType);
|
|
640
|
+
await fetchClaimTypes();
|
|
641
|
+
return { success: true };
|
|
642
|
+
} catch (err) {
|
|
643
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to create claim type";
|
|
644
|
+
setError(errorMessage);
|
|
645
|
+
setIsLoading(false);
|
|
646
|
+
return { success: false, error: errorMessage };
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
[service, fetchClaimTypes]
|
|
650
|
+
);
|
|
651
|
+
const updateClaimType = useCallback4(
|
|
652
|
+
async (claimType) => {
|
|
653
|
+
setIsLoading(true);
|
|
654
|
+
setError(null);
|
|
655
|
+
try {
|
|
656
|
+
await service.updateClaimType(claimType);
|
|
657
|
+
await fetchClaimTypes();
|
|
658
|
+
return { success: true };
|
|
659
|
+
} catch (err) {
|
|
660
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to update claim type";
|
|
661
|
+
setError(errorMessage);
|
|
662
|
+
setIsLoading(false);
|
|
663
|
+
return { success: false, error: errorMessage };
|
|
664
|
+
}
|
|
665
|
+
},
|
|
666
|
+
[service, fetchClaimTypes]
|
|
667
|
+
);
|
|
668
|
+
const deleteClaimType = useCallback4(
|
|
669
|
+
async (id) => {
|
|
670
|
+
setIsLoading(true);
|
|
671
|
+
setError(null);
|
|
672
|
+
try {
|
|
673
|
+
await service.deleteClaimType(id);
|
|
674
|
+
await fetchClaimTypes();
|
|
675
|
+
return { success: true };
|
|
676
|
+
} catch (err) {
|
|
677
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to delete claim type";
|
|
678
|
+
setError(errorMessage);
|
|
679
|
+
setIsLoading(false);
|
|
680
|
+
return { success: false, error: errorMessage };
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
[service, fetchClaimTypes]
|
|
684
|
+
);
|
|
685
|
+
const getClaims = useCallback4(
|
|
686
|
+
async (id, type) => {
|
|
687
|
+
try {
|
|
688
|
+
return await service.getClaims({ id, type });
|
|
689
|
+
} catch (err) {
|
|
690
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch claims";
|
|
691
|
+
setError(errorMessage);
|
|
692
|
+
return [];
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
[service]
|
|
696
|
+
);
|
|
697
|
+
const updateClaims = useCallback4(
|
|
698
|
+
async (id, type, claims) => {
|
|
699
|
+
setIsLoading(true);
|
|
700
|
+
setError(null);
|
|
701
|
+
try {
|
|
702
|
+
await service.updateClaims({ id, type, claims });
|
|
703
|
+
setIsLoading(false);
|
|
704
|
+
return { success: true };
|
|
705
|
+
} catch (err) {
|
|
706
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to update claims";
|
|
707
|
+
setError(errorMessage);
|
|
708
|
+
setIsLoading(false);
|
|
709
|
+
return { success: false, error: errorMessage };
|
|
710
|
+
}
|
|
711
|
+
},
|
|
712
|
+
[service]
|
|
713
|
+
);
|
|
714
|
+
const reset = useCallback4(() => {
|
|
715
|
+
setClaimTypes([]);
|
|
716
|
+
setTotalCount(0);
|
|
717
|
+
setClaimTypeNames([]);
|
|
718
|
+
setSelectedClaimType(null);
|
|
719
|
+
setIsLoading(false);
|
|
720
|
+
setError(null);
|
|
721
|
+
}, []);
|
|
722
|
+
return {
|
|
723
|
+
claimTypes,
|
|
724
|
+
totalCount,
|
|
725
|
+
claimTypeNames,
|
|
726
|
+
selectedClaimType,
|
|
727
|
+
isLoading,
|
|
728
|
+
error,
|
|
729
|
+
sortKey,
|
|
730
|
+
sortOrder,
|
|
731
|
+
fetchClaimTypes,
|
|
732
|
+
fetchClaimTypeNames,
|
|
733
|
+
getClaimTypeById,
|
|
734
|
+
createClaimType,
|
|
735
|
+
updateClaimType,
|
|
736
|
+
deleteClaimType,
|
|
737
|
+
setSelectedClaimType,
|
|
738
|
+
setSortKey,
|
|
739
|
+
setSortOrder,
|
|
740
|
+
reset,
|
|
741
|
+
getClaims,
|
|
742
|
+
updateClaims
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// src/components/Roles/RolesComponent.tsx
|
|
747
|
+
import { useEffect, useState as useState4, useCallback as useCallback5 } from "react";
|
|
748
|
+
import { useLocalization } from "@abpjs/core";
|
|
749
|
+
import { Modal, useConfirmation, Toaster, Alert, Button, Checkbox, FormField } from "@abpjs/theme-shared";
|
|
750
|
+
import { PermissionManagementModal } from "@abpjs/permission-management";
|
|
751
|
+
import {
|
|
752
|
+
Box,
|
|
753
|
+
Flex,
|
|
754
|
+
Input,
|
|
755
|
+
Table,
|
|
756
|
+
Spinner,
|
|
757
|
+
VStack,
|
|
758
|
+
Menu,
|
|
759
|
+
Text
|
|
760
|
+
} from "@chakra-ui/react";
|
|
761
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
762
|
+
var DEFAULT_FORM_STATE = {
|
|
763
|
+
name: "",
|
|
764
|
+
isDefault: false,
|
|
765
|
+
isPublic: false
|
|
766
|
+
};
|
|
767
|
+
function RolesComponent({
|
|
768
|
+
onRoleCreated,
|
|
769
|
+
onRoleUpdated,
|
|
770
|
+
onRoleDeleted
|
|
771
|
+
}) {
|
|
772
|
+
const { t } = useLocalization();
|
|
773
|
+
const confirmation = useConfirmation();
|
|
774
|
+
const {
|
|
775
|
+
roles,
|
|
776
|
+
selectedRole,
|
|
777
|
+
isLoading,
|
|
778
|
+
error,
|
|
779
|
+
fetchRoles,
|
|
780
|
+
getRoleById,
|
|
781
|
+
createRole,
|
|
782
|
+
updateRole,
|
|
783
|
+
deleteRole,
|
|
784
|
+
setSelectedRole
|
|
785
|
+
} = useRoles();
|
|
786
|
+
const [isModalOpen, setIsModalOpen] = useState4(false);
|
|
787
|
+
const [formState, setFormState] = useState4(DEFAULT_FORM_STATE);
|
|
788
|
+
const [isSubmitting, setIsSubmitting] = useState4(false);
|
|
789
|
+
const [isPermissionModalOpen, setIsPermissionModalOpen] = useState4(false);
|
|
790
|
+
const [permissionProviderKey, setPermissionProviderKey] = useState4("");
|
|
791
|
+
const [searchTerm, setSearchTerm] = useState4("");
|
|
792
|
+
useEffect(() => {
|
|
793
|
+
fetchRoles();
|
|
794
|
+
}, [fetchRoles]);
|
|
795
|
+
const filteredRoles = roles.filter(
|
|
796
|
+
(role) => !searchTerm || role.name.toLowerCase().includes(searchTerm.toLowerCase())
|
|
797
|
+
);
|
|
798
|
+
const handleAdd = useCallback5(() => {
|
|
799
|
+
setSelectedRole(null);
|
|
800
|
+
setFormState(DEFAULT_FORM_STATE);
|
|
801
|
+
setIsModalOpen(true);
|
|
802
|
+
}, [setSelectedRole]);
|
|
803
|
+
const handleEdit = useCallback5(
|
|
804
|
+
async (id) => {
|
|
805
|
+
const result = await getRoleById(id);
|
|
806
|
+
if (result.success && selectedRole) {
|
|
807
|
+
setFormState({
|
|
808
|
+
name: selectedRole.name || "",
|
|
809
|
+
isDefault: selectedRole.isDefault || false,
|
|
810
|
+
isPublic: selectedRole.isPublic || false
|
|
811
|
+
});
|
|
812
|
+
setIsModalOpen(true);
|
|
813
|
+
}
|
|
814
|
+
},
|
|
815
|
+
[getRoleById, selectedRole]
|
|
816
|
+
);
|
|
817
|
+
useEffect(() => {
|
|
818
|
+
if (selectedRole) {
|
|
819
|
+
setFormState({
|
|
820
|
+
name: selectedRole.name || "",
|
|
821
|
+
isDefault: selectedRole.isDefault || false,
|
|
822
|
+
isPublic: selectedRole.isPublic || false
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
}, [selectedRole]);
|
|
826
|
+
const handleDelete = useCallback5(
|
|
827
|
+
async (id, name) => {
|
|
828
|
+
const status = await confirmation.warn(
|
|
829
|
+
t("AbpIdentity::RoleDeletionConfirmationMessage", name),
|
|
830
|
+
t("AbpIdentity::AreYouSure")
|
|
831
|
+
);
|
|
832
|
+
if (status === Toaster.Status.confirm) {
|
|
833
|
+
const result = await deleteRole(id);
|
|
834
|
+
if (result.success) {
|
|
835
|
+
onRoleDeleted?.(id);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
},
|
|
839
|
+
[confirmation, t, deleteRole, onRoleDeleted]
|
|
840
|
+
);
|
|
841
|
+
const handleOpenPermissions = useCallback5((roleName) => {
|
|
842
|
+
setPermissionProviderKey(roleName);
|
|
843
|
+
setIsPermissionModalOpen(true);
|
|
844
|
+
}, []);
|
|
845
|
+
const handleSubmit = useCallback5(async () => {
|
|
846
|
+
if (!formState.name.trim()) return;
|
|
847
|
+
setIsSubmitting(true);
|
|
848
|
+
const roleData = {
|
|
849
|
+
name: formState.name.trim(),
|
|
850
|
+
isDefault: formState.isDefault,
|
|
851
|
+
isPublic: formState.isPublic
|
|
852
|
+
};
|
|
853
|
+
let result;
|
|
854
|
+
if (selectedRole?.id) {
|
|
855
|
+
result = await updateRole(selectedRole.id, roleData);
|
|
856
|
+
if (result.success) {
|
|
857
|
+
onRoleUpdated?.({ ...selectedRole, ...roleData });
|
|
858
|
+
}
|
|
859
|
+
} else {
|
|
860
|
+
result = await createRole(roleData);
|
|
861
|
+
if (result.success) {
|
|
862
|
+
onRoleCreated?.({ ...roleData, id: "", isStatic: false, concurrencyStamp: "" });
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
setIsSubmitting(false);
|
|
866
|
+
if (result.success) {
|
|
867
|
+
setIsModalOpen(false);
|
|
868
|
+
setFormState(DEFAULT_FORM_STATE);
|
|
869
|
+
setSelectedRole(null);
|
|
870
|
+
}
|
|
871
|
+
}, [formState, selectedRole, updateRole, createRole, onRoleCreated, onRoleUpdated, setSelectedRole]);
|
|
872
|
+
const handleModalClose = useCallback5(() => {
|
|
873
|
+
setIsModalOpen(false);
|
|
874
|
+
setFormState(DEFAULT_FORM_STATE);
|
|
875
|
+
setSelectedRole(null);
|
|
876
|
+
}, [setSelectedRole]);
|
|
877
|
+
const handleInputChange = useCallback5(
|
|
878
|
+
(field, value) => {
|
|
879
|
+
setFormState((prev) => ({ ...prev, [field]: value }));
|
|
880
|
+
},
|
|
881
|
+
[]
|
|
882
|
+
);
|
|
883
|
+
return /* @__PURE__ */ jsxs(Box, { id: "identity-roles-wrapper", className: "card", p: 4, children: [
|
|
884
|
+
/* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", mb: 4, children: [
|
|
885
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "xl", fontWeight: "bold", children: t("AbpIdentity::Roles") }),
|
|
886
|
+
/* @__PURE__ */ jsx(Button, { colorPalette: "blue", onClick: handleAdd, children: t("AbpIdentity::NewRole") })
|
|
887
|
+
] }),
|
|
888
|
+
/* @__PURE__ */ jsx(Box, { mb: 4, children: /* @__PURE__ */ jsx(
|
|
889
|
+
Input,
|
|
890
|
+
{
|
|
891
|
+
placeholder: t("AbpIdentity::Search"),
|
|
892
|
+
value: searchTerm,
|
|
893
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
894
|
+
maxW: "300px"
|
|
895
|
+
}
|
|
896
|
+
) }),
|
|
897
|
+
error && /* @__PURE__ */ jsx(Alert, { status: "error", mb: 4, children: error }),
|
|
898
|
+
isLoading && roles.length === 0 && /* @__PURE__ */ jsx(Flex, { justify: "center", py: 8, children: /* @__PURE__ */ jsx(Spinner, { size: "lg" }) }),
|
|
899
|
+
roles.length > 0 && /* @__PURE__ */ jsxs(Table.Root, { variant: "outline", children: [
|
|
900
|
+
/* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
|
|
901
|
+
/* @__PURE__ */ jsx(Table.ColumnHeader, { children: t("AbpIdentity::Actions") }),
|
|
902
|
+
/* @__PURE__ */ jsx(Table.ColumnHeader, { children: t("AbpIdentity::RoleName") })
|
|
903
|
+
] }) }),
|
|
904
|
+
/* @__PURE__ */ jsx(Table.Body, { children: filteredRoles.map((role) => /* @__PURE__ */ jsxs(Table.Row, { children: [
|
|
905
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsxs(Menu.Root, { children: [
|
|
906
|
+
/* @__PURE__ */ jsx(Menu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "sm", colorPalette: "blue", children: t("AbpIdentity::Actions") }) }),
|
|
907
|
+
/* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsxs(Menu.Content, { children: [
|
|
908
|
+
/* @__PURE__ */ jsx(Menu.Item, { value: "edit", onClick: () => handleEdit(role.id), children: t("AbpIdentity::Edit") }),
|
|
909
|
+
/* @__PURE__ */ jsx(Menu.Item, { value: "permissions", onClick: () => handleOpenPermissions(role.name), children: t("AbpIdentity::Permissions") }),
|
|
910
|
+
!role.isStatic && /* @__PURE__ */ jsx(
|
|
911
|
+
Menu.Item,
|
|
912
|
+
{
|
|
913
|
+
value: "delete",
|
|
914
|
+
color: "red.500",
|
|
915
|
+
onClick: () => handleDelete(role.id, role.name),
|
|
916
|
+
children: t("AbpIdentity::Delete")
|
|
917
|
+
}
|
|
918
|
+
)
|
|
919
|
+
] }) })
|
|
920
|
+
] }) }),
|
|
921
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: role.name })
|
|
922
|
+
] }, role.id)) })
|
|
923
|
+
] }),
|
|
924
|
+
!isLoading && roles.length === 0 && /* @__PURE__ */ jsx(Text, { textAlign: "center", color: "gray.500", py: 8, children: t("AbpIdentity::NoRolesFound") }),
|
|
925
|
+
/* @__PURE__ */ jsx(
|
|
926
|
+
Modal,
|
|
927
|
+
{
|
|
928
|
+
visible: isModalOpen,
|
|
929
|
+
onVisibleChange: setIsModalOpen,
|
|
930
|
+
header: selectedRole?.id ? t("AbpIdentity::Edit") : t("AbpIdentity::NewRole"),
|
|
931
|
+
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
932
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleModalClose, disabled: isSubmitting, children: t("AbpIdentity::Cancel") }),
|
|
933
|
+
/* @__PURE__ */ jsx(
|
|
934
|
+
Button,
|
|
935
|
+
{
|
|
936
|
+
colorPalette: "blue",
|
|
937
|
+
onClick: handleSubmit,
|
|
938
|
+
loading: isSubmitting,
|
|
939
|
+
disabled: !formState.name.trim(),
|
|
940
|
+
children: t("AbpIdentity::Save")
|
|
941
|
+
}
|
|
942
|
+
)
|
|
943
|
+
] }),
|
|
944
|
+
children: /* @__PURE__ */ jsxs(VStack, { gap: 4, align: "stretch", children: [
|
|
945
|
+
/* @__PURE__ */ jsx(FormField, { label: t("AbpIdentity::RoleName"), required: true, children: /* @__PURE__ */ jsx(
|
|
946
|
+
Input,
|
|
947
|
+
{
|
|
948
|
+
value: formState.name,
|
|
949
|
+
onChange: (e) => handleInputChange("name", e.target.value),
|
|
950
|
+
maxLength: 256,
|
|
951
|
+
placeholder: t("AbpIdentity::RoleName")
|
|
952
|
+
}
|
|
953
|
+
) }),
|
|
954
|
+
/* @__PURE__ */ jsx(
|
|
955
|
+
Checkbox,
|
|
956
|
+
{
|
|
957
|
+
checked: formState.isDefault,
|
|
958
|
+
onChange: (e) => handleInputChange("isDefault", e.target.checked),
|
|
959
|
+
children: t("AbpIdentity::DisplayName:IsDefault")
|
|
960
|
+
}
|
|
961
|
+
),
|
|
962
|
+
/* @__PURE__ */ jsx(
|
|
963
|
+
Checkbox,
|
|
964
|
+
{
|
|
965
|
+
checked: formState.isPublic,
|
|
966
|
+
onChange: (e) => handleInputChange("isPublic", e.target.checked),
|
|
967
|
+
children: t("AbpIdentity::DisplayName:IsPublic")
|
|
968
|
+
}
|
|
969
|
+
)
|
|
970
|
+
] })
|
|
971
|
+
}
|
|
972
|
+
),
|
|
973
|
+
/* @__PURE__ */ jsx(
|
|
974
|
+
PermissionManagementModal,
|
|
975
|
+
{
|
|
976
|
+
visible: isPermissionModalOpen,
|
|
977
|
+
onVisibleChange: setIsPermissionModalOpen,
|
|
978
|
+
providerName: "R",
|
|
979
|
+
providerKey: permissionProviderKey
|
|
980
|
+
}
|
|
981
|
+
)
|
|
982
|
+
] });
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// src/components/Users/UsersComponent.tsx
|
|
986
|
+
import { useEffect as useEffect2, useState as useState5, useCallback as useCallback6, useMemo as useMemo5 } from "react";
|
|
987
|
+
import { useLocalization as useLocalization2 } from "@abpjs/core";
|
|
988
|
+
import { Modal as Modal2, useConfirmation as useConfirmation2, Toaster as Toaster2, Alert as Alert2, Button as Button2, Checkbox as Checkbox2, FormField as FormField2 } from "@abpjs/theme-shared";
|
|
989
|
+
import { PermissionManagementModal as PermissionManagementModal2 } from "@abpjs/permission-management";
|
|
990
|
+
import {
|
|
991
|
+
Box as Box2,
|
|
992
|
+
Flex as Flex2,
|
|
993
|
+
Input as Input2,
|
|
994
|
+
Table as Table2,
|
|
995
|
+
Spinner as Spinner2,
|
|
996
|
+
VStack as VStack2,
|
|
997
|
+
Menu as Menu2,
|
|
998
|
+
Text as Text2,
|
|
999
|
+
Tabs,
|
|
1000
|
+
SimpleGrid
|
|
1001
|
+
} from "@chakra-ui/react";
|
|
1002
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1003
|
+
var DEFAULT_FORM_STATE2 = {
|
|
1004
|
+
userName: "",
|
|
1005
|
+
name: "",
|
|
1006
|
+
surname: "",
|
|
1007
|
+
email: "",
|
|
1008
|
+
phoneNumber: "",
|
|
1009
|
+
password: "",
|
|
1010
|
+
lockoutEnabled: true,
|
|
1011
|
+
twoFactorEnabled: true,
|
|
1012
|
+
roleNames: []
|
|
1013
|
+
};
|
|
1014
|
+
function UsersComponent({
|
|
1015
|
+
onUserCreated,
|
|
1016
|
+
onUserUpdated,
|
|
1017
|
+
onUserDeleted
|
|
1018
|
+
}) {
|
|
1019
|
+
const { t } = useLocalization2();
|
|
1020
|
+
const confirmation = useConfirmation2();
|
|
1021
|
+
const {
|
|
1022
|
+
users,
|
|
1023
|
+
totalCount,
|
|
1024
|
+
selectedUser,
|
|
1025
|
+
selectedUserRoles,
|
|
1026
|
+
isLoading,
|
|
1027
|
+
error,
|
|
1028
|
+
pageQuery,
|
|
1029
|
+
fetchUsers,
|
|
1030
|
+
getUserById,
|
|
1031
|
+
getUserRoles,
|
|
1032
|
+
createUser,
|
|
1033
|
+
updateUser,
|
|
1034
|
+
deleteUser,
|
|
1035
|
+
setSelectedUser,
|
|
1036
|
+
setPageQuery
|
|
1037
|
+
} = useUsers();
|
|
1038
|
+
const { roles, fetchRoles } = useRoles();
|
|
1039
|
+
const [isModalOpen, setIsModalOpen] = useState5(false);
|
|
1040
|
+
const [formState, setFormState] = useState5(DEFAULT_FORM_STATE2);
|
|
1041
|
+
const [isSubmitting, setIsSubmitting] = useState5(false);
|
|
1042
|
+
const [isPermissionModalOpen, setIsPermissionModalOpen] = useState5(false);
|
|
1043
|
+
const [permissionProviderKey, setPermissionProviderKey] = useState5("");
|
|
1044
|
+
const [searchTerm, setSearchTerm] = useState5("");
|
|
1045
|
+
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState5("");
|
|
1046
|
+
useEffect2(() => {
|
|
1047
|
+
fetchRoles();
|
|
1048
|
+
fetchUsers();
|
|
1049
|
+
}, [fetchRoles, fetchUsers]);
|
|
1050
|
+
useEffect2(() => {
|
|
1051
|
+
const timer = setTimeout(() => {
|
|
1052
|
+
setDebouncedSearchTerm(searchTerm);
|
|
1053
|
+
}, 300);
|
|
1054
|
+
return () => clearTimeout(timer);
|
|
1055
|
+
}, [searchTerm]);
|
|
1056
|
+
useEffect2(() => {
|
|
1057
|
+
const newQuery = {
|
|
1058
|
+
...pageQuery,
|
|
1059
|
+
filter: debouncedSearchTerm || void 0,
|
|
1060
|
+
skipCount: 0
|
|
1061
|
+
};
|
|
1062
|
+
setPageQuery(newQuery);
|
|
1063
|
+
fetchUsers(newQuery);
|
|
1064
|
+
}, [debouncedSearchTerm]);
|
|
1065
|
+
const selectedRoleNames = useMemo5(() => {
|
|
1066
|
+
return selectedUserRoles.map((role) => role.name);
|
|
1067
|
+
}, [selectedUserRoles]);
|
|
1068
|
+
const handleAdd = useCallback6(() => {
|
|
1069
|
+
setSelectedUser(null);
|
|
1070
|
+
setFormState(DEFAULT_FORM_STATE2);
|
|
1071
|
+
setIsModalOpen(true);
|
|
1072
|
+
}, [setSelectedUser]);
|
|
1073
|
+
const handleEdit = useCallback6(
|
|
1074
|
+
async (id) => {
|
|
1075
|
+
await Promise.all([getUserById(id), getUserRoles(id)]);
|
|
1076
|
+
setIsModalOpen(true);
|
|
1077
|
+
},
|
|
1078
|
+
[getUserById, getUserRoles]
|
|
1079
|
+
);
|
|
1080
|
+
useEffect2(() => {
|
|
1081
|
+
if (selectedUser) {
|
|
1082
|
+
setFormState({
|
|
1083
|
+
userName: selectedUser.userName || "",
|
|
1084
|
+
name: selectedUser.name || "",
|
|
1085
|
+
surname: selectedUser.surname || "",
|
|
1086
|
+
email: selectedUser.email || "",
|
|
1087
|
+
phoneNumber: selectedUser.phoneNumber || "",
|
|
1088
|
+
password: "",
|
|
1089
|
+
lockoutEnabled: selectedUser.lockoutEnabled ?? true,
|
|
1090
|
+
twoFactorEnabled: selectedUser.twoFactorEnabled ?? true,
|
|
1091
|
+
roleNames: selectedRoleNames
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
}, [selectedUser, selectedRoleNames]);
|
|
1095
|
+
const handleDelete = useCallback6(
|
|
1096
|
+
async (id, userName) => {
|
|
1097
|
+
const status = await confirmation.warn(
|
|
1098
|
+
t("AbpIdentity::UserDeletionConfirmationMessage", userName),
|
|
1099
|
+
t("AbpIdentity::AreYouSure")
|
|
1100
|
+
);
|
|
1101
|
+
if (status === Toaster2.Status.confirm) {
|
|
1102
|
+
const result = await deleteUser(id);
|
|
1103
|
+
if (result.success) {
|
|
1104
|
+
onUserDeleted?.(id);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
},
|
|
1108
|
+
[confirmation, t, deleteUser, onUserDeleted]
|
|
1109
|
+
);
|
|
1110
|
+
const handleOpenPermissions = useCallback6((userId) => {
|
|
1111
|
+
setPermissionProviderKey(userId);
|
|
1112
|
+
setIsPermissionModalOpen(true);
|
|
1113
|
+
}, []);
|
|
1114
|
+
const handleSubmit = useCallback6(async () => {
|
|
1115
|
+
if (!formState.userName.trim() || !formState.email.trim()) return;
|
|
1116
|
+
if (!selectedUser?.id && !formState.password) return;
|
|
1117
|
+
setIsSubmitting(true);
|
|
1118
|
+
const userData = {
|
|
1119
|
+
userName: formState.userName.trim(),
|
|
1120
|
+
name: formState.name.trim(),
|
|
1121
|
+
surname: formState.surname.trim(),
|
|
1122
|
+
email: formState.email.trim(),
|
|
1123
|
+
phoneNumber: formState.phoneNumber.trim(),
|
|
1124
|
+
password: formState.password,
|
|
1125
|
+
lockoutEnabled: formState.lockoutEnabled,
|
|
1126
|
+
twoFactorEnabled: formState.twoFactorEnabled,
|
|
1127
|
+
roleNames: formState.roleNames
|
|
1128
|
+
};
|
|
1129
|
+
let result;
|
|
1130
|
+
if (selectedUser?.id) {
|
|
1131
|
+
result = await updateUser(selectedUser.id, userData);
|
|
1132
|
+
if (result.success) {
|
|
1133
|
+
onUserUpdated?.({
|
|
1134
|
+
...selectedUser,
|
|
1135
|
+
...userData
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
} else {
|
|
1139
|
+
result = await createUser(userData);
|
|
1140
|
+
if (result.success) {
|
|
1141
|
+
onUserCreated?.({
|
|
1142
|
+
...userData,
|
|
1143
|
+
id: "",
|
|
1144
|
+
tenantId: "",
|
|
1145
|
+
emailConfirmed: false,
|
|
1146
|
+
phoneNumberConfirmed: false,
|
|
1147
|
+
isLockedOut: false,
|
|
1148
|
+
concurrencyStamp: ""
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
setIsSubmitting(false);
|
|
1153
|
+
if (result.success) {
|
|
1154
|
+
setIsModalOpen(false);
|
|
1155
|
+
setFormState(DEFAULT_FORM_STATE2);
|
|
1156
|
+
setSelectedUser(null);
|
|
1157
|
+
}
|
|
1158
|
+
}, [formState, selectedUser, updateUser, createUser, onUserCreated, onUserUpdated, setSelectedUser]);
|
|
1159
|
+
const handleModalClose = useCallback6(() => {
|
|
1160
|
+
setIsModalOpen(false);
|
|
1161
|
+
setFormState(DEFAULT_FORM_STATE2);
|
|
1162
|
+
setSelectedUser(null);
|
|
1163
|
+
}, [setSelectedUser]);
|
|
1164
|
+
const handleInputChange = useCallback6(
|
|
1165
|
+
(field, value) => {
|
|
1166
|
+
setFormState((prev) => ({ ...prev, [field]: value }));
|
|
1167
|
+
},
|
|
1168
|
+
[]
|
|
1169
|
+
);
|
|
1170
|
+
const handleRoleChange = useCallback6((roleName, checked) => {
|
|
1171
|
+
setFormState((prev) => ({
|
|
1172
|
+
...prev,
|
|
1173
|
+
roleNames: checked ? [...prev.roleNames, roleName] : prev.roleNames.filter((name) => name !== roleName)
|
|
1174
|
+
}));
|
|
1175
|
+
}, []);
|
|
1176
|
+
const handlePageChange = useCallback6(
|
|
1177
|
+
(newSkipCount) => {
|
|
1178
|
+
const newQuery = { ...pageQuery, skipCount: newSkipCount };
|
|
1179
|
+
setPageQuery(newQuery);
|
|
1180
|
+
fetchUsers(newQuery);
|
|
1181
|
+
},
|
|
1182
|
+
[pageQuery, setPageQuery, fetchUsers]
|
|
1183
|
+
);
|
|
1184
|
+
return /* @__PURE__ */ jsxs2(Box2, { id: "identity-users-wrapper", className: "card", p: 4, children: [
|
|
1185
|
+
/* @__PURE__ */ jsxs2(Flex2, { justify: "space-between", align: "center", mb: 4, children: [
|
|
1186
|
+
/* @__PURE__ */ jsx2(Text2, { fontSize: "xl", fontWeight: "bold", children: t("AbpIdentity::Users") }),
|
|
1187
|
+
/* @__PURE__ */ jsx2(Button2, { colorPalette: "blue", onClick: handleAdd, children: t("AbpIdentity::NewUser") })
|
|
1188
|
+
] }),
|
|
1189
|
+
/* @__PURE__ */ jsx2(Box2, { mb: 4, children: /* @__PURE__ */ jsx2(
|
|
1190
|
+
Input2,
|
|
1191
|
+
{
|
|
1192
|
+
placeholder: t("AbpIdentity::Search"),
|
|
1193
|
+
value: searchTerm,
|
|
1194
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
1195
|
+
maxW: "300px"
|
|
1196
|
+
}
|
|
1197
|
+
) }),
|
|
1198
|
+
error && /* @__PURE__ */ jsx2(Alert2, { status: "error", mb: 4, children: error }),
|
|
1199
|
+
isLoading && users.length === 0 && /* @__PURE__ */ jsx2(Flex2, { justify: "center", py: 8, children: /* @__PURE__ */ jsx2(Spinner2, { size: "lg" }) }),
|
|
1200
|
+
users.length > 0 && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1201
|
+
/* @__PURE__ */ jsxs2(Table2.Root, { variant: "outline", children: [
|
|
1202
|
+
/* @__PURE__ */ jsx2(Table2.Header, { children: /* @__PURE__ */ jsxs2(Table2.Row, { children: [
|
|
1203
|
+
/* @__PURE__ */ jsx2(Table2.ColumnHeader, { children: t("AbpIdentity::Actions") }),
|
|
1204
|
+
/* @__PURE__ */ jsx2(Table2.ColumnHeader, { children: t("AbpIdentity::UserName") }),
|
|
1205
|
+
/* @__PURE__ */ jsx2(Table2.ColumnHeader, { children: t("AbpIdentity::EmailAddress") }),
|
|
1206
|
+
/* @__PURE__ */ jsx2(Table2.ColumnHeader, { children: t("AbpIdentity::PhoneNumber") })
|
|
1207
|
+
] }) }),
|
|
1208
|
+
/* @__PURE__ */ jsx2(Table2.Body, { children: users.map((user) => /* @__PURE__ */ jsxs2(Table2.Row, { children: [
|
|
1209
|
+
/* @__PURE__ */ jsx2(Table2.Cell, { children: /* @__PURE__ */ jsxs2(Menu2.Root, { children: [
|
|
1210
|
+
/* @__PURE__ */ jsx2(Menu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx2(Button2, { size: "sm", colorPalette: "blue", children: t("AbpIdentity::Actions") }) }),
|
|
1211
|
+
/* @__PURE__ */ jsx2(Menu2.Positioner, { children: /* @__PURE__ */ jsxs2(Menu2.Content, { children: [
|
|
1212
|
+
/* @__PURE__ */ jsx2(Menu2.Item, { value: "edit", onClick: () => handleEdit(user.id), children: t("AbpIdentity::Edit") }),
|
|
1213
|
+
/* @__PURE__ */ jsx2(Menu2.Item, { value: "permissions", onClick: () => handleOpenPermissions(user.id), children: t("AbpIdentity::Permissions") }),
|
|
1214
|
+
/* @__PURE__ */ jsx2(
|
|
1215
|
+
Menu2.Item,
|
|
1216
|
+
{
|
|
1217
|
+
value: "delete",
|
|
1218
|
+
color: "red.500",
|
|
1219
|
+
onClick: () => handleDelete(user.id, user.userName),
|
|
1220
|
+
children: t("AbpIdentity::Delete")
|
|
1221
|
+
}
|
|
1222
|
+
)
|
|
1223
|
+
] }) })
|
|
1224
|
+
] }) }),
|
|
1225
|
+
/* @__PURE__ */ jsx2(Table2.Cell, { children: user.userName }),
|
|
1226
|
+
/* @__PURE__ */ jsx2(Table2.Cell, { children: user.email }),
|
|
1227
|
+
/* @__PURE__ */ jsx2(Table2.Cell, { children: user.phoneNumber })
|
|
1228
|
+
] }, user.id)) })
|
|
1229
|
+
] }),
|
|
1230
|
+
/* @__PURE__ */ jsxs2(Flex2, { justify: "space-between", align: "center", mt: 4, children: [
|
|
1231
|
+
/* @__PURE__ */ jsxs2(Text2, { color: "gray.600", children: [
|
|
1232
|
+
t("AbpIdentity::TotalCount"),
|
|
1233
|
+
": ",
|
|
1234
|
+
totalCount
|
|
1235
|
+
] }),
|
|
1236
|
+
/* @__PURE__ */ jsxs2(Flex2, { gap: 2, children: [
|
|
1237
|
+
/* @__PURE__ */ jsx2(
|
|
1238
|
+
Button2,
|
|
1239
|
+
{
|
|
1240
|
+
size: "sm",
|
|
1241
|
+
disabled: (pageQuery.skipCount || 0) === 0,
|
|
1242
|
+
onClick: () => handlePageChange(
|
|
1243
|
+
Math.max(0, (pageQuery.skipCount || 0) - (pageQuery.maxResultCount || 10))
|
|
1244
|
+
),
|
|
1245
|
+
children: t("AbpIdentity::Previous")
|
|
1246
|
+
}
|
|
1247
|
+
),
|
|
1248
|
+
/* @__PURE__ */ jsx2(
|
|
1249
|
+
Button2,
|
|
1250
|
+
{
|
|
1251
|
+
size: "sm",
|
|
1252
|
+
disabled: (pageQuery.skipCount || 0) + (pageQuery.maxResultCount || 10) >= totalCount,
|
|
1253
|
+
onClick: () => handlePageChange((pageQuery.skipCount || 0) + (pageQuery.maxResultCount || 10)),
|
|
1254
|
+
children: t("AbpIdentity::Next")
|
|
1255
|
+
}
|
|
1256
|
+
)
|
|
1257
|
+
] })
|
|
1258
|
+
] })
|
|
1259
|
+
] }),
|
|
1260
|
+
!isLoading && users.length === 0 && /* @__PURE__ */ jsx2(Text2, { textAlign: "center", color: "gray.500", py: 8, children: t("AbpIdentity::NoUsersFound") }),
|
|
1261
|
+
/* @__PURE__ */ jsx2(
|
|
1262
|
+
Modal2,
|
|
1263
|
+
{
|
|
1264
|
+
visible: isModalOpen,
|
|
1265
|
+
onVisibleChange: setIsModalOpen,
|
|
1266
|
+
size: "lg",
|
|
1267
|
+
header: selectedUser?.id ? t("AbpIdentity::Edit") : t("AbpIdentity::NewUser"),
|
|
1268
|
+
footer: /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1269
|
+
/* @__PURE__ */ jsx2(Button2, { variant: "outline", onClick: handleModalClose, disabled: isSubmitting, children: t("AbpIdentity::Cancel") }),
|
|
1270
|
+
/* @__PURE__ */ jsx2(
|
|
1271
|
+
Button2,
|
|
1272
|
+
{
|
|
1273
|
+
colorPalette: "blue",
|
|
1274
|
+
onClick: handleSubmit,
|
|
1275
|
+
loading: isSubmitting,
|
|
1276
|
+
disabled: !formState.userName.trim() || !formState.email.trim() || !selectedUser?.id && !formState.password,
|
|
1277
|
+
children: t("AbpIdentity::Save")
|
|
1278
|
+
}
|
|
1279
|
+
)
|
|
1280
|
+
] }),
|
|
1281
|
+
children: /* @__PURE__ */ jsxs2(Tabs.Root, { defaultValue: "info", children: [
|
|
1282
|
+
/* @__PURE__ */ jsxs2(Tabs.List, { children: [
|
|
1283
|
+
/* @__PURE__ */ jsx2(Tabs.Trigger, { value: "info", children: t("AbpIdentity::UserInformations") }),
|
|
1284
|
+
/* @__PURE__ */ jsx2(Tabs.Trigger, { value: "roles", children: t("AbpIdentity::Roles") })
|
|
1285
|
+
] }),
|
|
1286
|
+
/* @__PURE__ */ jsx2(Tabs.Content, { value: "info", children: /* @__PURE__ */ jsxs2(VStack2, { gap: 4, align: "stretch", pt: 4, children: [
|
|
1287
|
+
/* @__PURE__ */ jsx2(FormField2, { label: t("AbpIdentity::UserName"), required: true, children: /* @__PURE__ */ jsx2(
|
|
1288
|
+
Input2,
|
|
1289
|
+
{
|
|
1290
|
+
value: formState.userName,
|
|
1291
|
+
onChange: (e) => handleInputChange("userName", e.target.value),
|
|
1292
|
+
maxLength: 256
|
|
1293
|
+
}
|
|
1294
|
+
) }),
|
|
1295
|
+
/* @__PURE__ */ jsxs2(SimpleGrid, { columns: 2, gap: 4, children: [
|
|
1296
|
+
/* @__PURE__ */ jsx2(FormField2, { label: t("AbpIdentity::Name"), children: /* @__PURE__ */ jsx2(
|
|
1297
|
+
Input2,
|
|
1298
|
+
{
|
|
1299
|
+
value: formState.name,
|
|
1300
|
+
onChange: (e) => handleInputChange("name", e.target.value),
|
|
1301
|
+
maxLength: 64
|
|
1302
|
+
}
|
|
1303
|
+
) }),
|
|
1304
|
+
/* @__PURE__ */ jsx2(FormField2, { label: t("AbpIdentity::DisplayName:Surname"), children: /* @__PURE__ */ jsx2(
|
|
1305
|
+
Input2,
|
|
1306
|
+
{
|
|
1307
|
+
value: formState.surname,
|
|
1308
|
+
onChange: (e) => handleInputChange("surname", e.target.value),
|
|
1309
|
+
maxLength: 64
|
|
1310
|
+
}
|
|
1311
|
+
) })
|
|
1312
|
+
] }),
|
|
1313
|
+
/* @__PURE__ */ jsx2(FormField2, { label: t("AbpIdentity::Password"), required: !selectedUser?.id, children: /* @__PURE__ */ jsx2(
|
|
1314
|
+
Input2,
|
|
1315
|
+
{
|
|
1316
|
+
type: "password",
|
|
1317
|
+
value: formState.password,
|
|
1318
|
+
onChange: (e) => handleInputChange("password", e.target.value),
|
|
1319
|
+
autoComplete: "new-password",
|
|
1320
|
+
maxLength: 32,
|
|
1321
|
+
placeholder: selectedUser?.id ? t("AbpIdentity::LeaveBlankToKeepCurrent") : ""
|
|
1322
|
+
}
|
|
1323
|
+
) }),
|
|
1324
|
+
/* @__PURE__ */ jsx2(FormField2, { label: t("AbpIdentity::EmailAddress"), required: true, children: /* @__PURE__ */ jsx2(
|
|
1325
|
+
Input2,
|
|
1326
|
+
{
|
|
1327
|
+
type: "email",
|
|
1328
|
+
value: formState.email,
|
|
1329
|
+
onChange: (e) => handleInputChange("email", e.target.value),
|
|
1330
|
+
maxLength: 256
|
|
1331
|
+
}
|
|
1332
|
+
) }),
|
|
1333
|
+
/* @__PURE__ */ jsx2(FormField2, { label: t("AbpIdentity::PhoneNumber"), children: /* @__PURE__ */ jsx2(
|
|
1334
|
+
Input2,
|
|
1335
|
+
{
|
|
1336
|
+
value: formState.phoneNumber,
|
|
1337
|
+
onChange: (e) => handleInputChange("phoneNumber", e.target.value),
|
|
1338
|
+
maxLength: 16
|
|
1339
|
+
}
|
|
1340
|
+
) }),
|
|
1341
|
+
/* @__PURE__ */ jsx2(
|
|
1342
|
+
Checkbox2,
|
|
1343
|
+
{
|
|
1344
|
+
checked: formState.lockoutEnabled,
|
|
1345
|
+
onChange: (e) => handleInputChange("lockoutEnabled", e.target.checked),
|
|
1346
|
+
children: t("AbpIdentity::DisplayName:LockoutEnabled")
|
|
1347
|
+
}
|
|
1348
|
+
),
|
|
1349
|
+
/* @__PURE__ */ jsx2(
|
|
1350
|
+
Checkbox2,
|
|
1351
|
+
{
|
|
1352
|
+
checked: formState.twoFactorEnabled,
|
|
1353
|
+
onChange: (e) => handleInputChange("twoFactorEnabled", e.target.checked),
|
|
1354
|
+
children: t("AbpIdentity::DisplayName:TwoFactorEnabled")
|
|
1355
|
+
}
|
|
1356
|
+
)
|
|
1357
|
+
] }) }),
|
|
1358
|
+
/* @__PURE__ */ jsx2(Tabs.Content, { value: "roles", children: /* @__PURE__ */ jsxs2(VStack2, { gap: 2, align: "stretch", pt: 4, children: [
|
|
1359
|
+
roles.map((role) => /* @__PURE__ */ jsx2(
|
|
1360
|
+
Checkbox2,
|
|
1361
|
+
{
|
|
1362
|
+
checked: formState.roleNames.includes(role.name),
|
|
1363
|
+
onChange: (e) => handleRoleChange(role.name, e.target.checked),
|
|
1364
|
+
children: role.name
|
|
1365
|
+
},
|
|
1366
|
+
role.id
|
|
1367
|
+
)),
|
|
1368
|
+
roles.length === 0 && /* @__PURE__ */ jsx2(Text2, { color: "gray.500", children: t("AbpIdentity::NoRolesFound") })
|
|
1369
|
+
] }) })
|
|
1370
|
+
] })
|
|
1371
|
+
}
|
|
1372
|
+
),
|
|
1373
|
+
/* @__PURE__ */ jsx2(
|
|
1374
|
+
PermissionManagementModal2,
|
|
1375
|
+
{
|
|
1376
|
+
visible: isPermissionModalOpen,
|
|
1377
|
+
onVisibleChange: setIsPermissionModalOpen,
|
|
1378
|
+
providerName: "U",
|
|
1379
|
+
providerKey: permissionProviderKey
|
|
1380
|
+
}
|
|
1381
|
+
)
|
|
1382
|
+
] });
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
// src/components/Claims/ClaimsComponent.tsx
|
|
1386
|
+
import { useEffect as useEffect3, useState as useState6, useCallback as useCallback7 } from "react";
|
|
1387
|
+
import { useLocalization as useLocalization3 } from "@abpjs/core";
|
|
1388
|
+
import { Modal as Modal3, useConfirmation as useConfirmation3, Toaster as Toaster3, Alert as Alert3, Button as Button3, FormField as FormField3 } from "@abpjs/theme-shared";
|
|
1389
|
+
import {
|
|
1390
|
+
Box as Box3,
|
|
1391
|
+
Flex as Flex3,
|
|
1392
|
+
Input as Input3,
|
|
1393
|
+
Table as Table3,
|
|
1394
|
+
Spinner as Spinner3,
|
|
1395
|
+
VStack as VStack3,
|
|
1396
|
+
Menu as Menu3,
|
|
1397
|
+
Text as Text3,
|
|
1398
|
+
Textarea
|
|
1399
|
+
} from "@chakra-ui/react";
|
|
1400
|
+
import { NativeSelectRoot, NativeSelectField } from "@chakra-ui/react";
|
|
1401
|
+
import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1402
|
+
var DEFAULT_FORM_STATE3 = {
|
|
1403
|
+
name: "",
|
|
1404
|
+
required: false,
|
|
1405
|
+
regex: "",
|
|
1406
|
+
regexDescription: "",
|
|
1407
|
+
description: "",
|
|
1408
|
+
valueType: 0
|
|
1409
|
+
};
|
|
1410
|
+
var VALUE_TYPE_OPTIONS = [
|
|
1411
|
+
{ value: 0, label: "String" },
|
|
1412
|
+
{ value: 1, label: "Int" },
|
|
1413
|
+
{ value: 2, label: "Boolean" },
|
|
1414
|
+
{ value: 3, label: "DateTime" }
|
|
1415
|
+
];
|
|
1416
|
+
function getValueTypeName(valueType) {
|
|
1417
|
+
const option = VALUE_TYPE_OPTIONS.find((opt) => opt.value === valueType);
|
|
1418
|
+
return option?.label || "String";
|
|
1419
|
+
}
|
|
1420
|
+
function ClaimsComponent({
|
|
1421
|
+
onClaimTypeCreated,
|
|
1422
|
+
onClaimTypeUpdated,
|
|
1423
|
+
onClaimTypeDeleted
|
|
1424
|
+
}) {
|
|
1425
|
+
const { t } = useLocalization3();
|
|
1426
|
+
const confirmation = useConfirmation3();
|
|
1427
|
+
const {
|
|
1428
|
+
claimTypes,
|
|
1429
|
+
selectedClaimType,
|
|
1430
|
+
isLoading,
|
|
1431
|
+
error,
|
|
1432
|
+
fetchClaimTypes,
|
|
1433
|
+
getClaimTypeById,
|
|
1434
|
+
createClaimType,
|
|
1435
|
+
updateClaimType,
|
|
1436
|
+
deleteClaimType,
|
|
1437
|
+
setSelectedClaimType
|
|
1438
|
+
} = useClaims();
|
|
1439
|
+
const [isModalOpen, setIsModalOpen] = useState6(false);
|
|
1440
|
+
const [formState, setFormState] = useState6(DEFAULT_FORM_STATE3);
|
|
1441
|
+
const [isSubmitting, setIsSubmitting] = useState6(false);
|
|
1442
|
+
const [searchTerm, setSearchTerm] = useState6("");
|
|
1443
|
+
useEffect3(() => {
|
|
1444
|
+
fetchClaimTypes();
|
|
1445
|
+
}, [fetchClaimTypes]);
|
|
1446
|
+
const filteredClaimTypes = claimTypes.filter(
|
|
1447
|
+
(claim) => !searchTerm || claim.name.toLowerCase().includes(searchTerm.toLowerCase())
|
|
1448
|
+
);
|
|
1449
|
+
const handleAdd = useCallback7(() => {
|
|
1450
|
+
setSelectedClaimType(null);
|
|
1451
|
+
setFormState(DEFAULT_FORM_STATE3);
|
|
1452
|
+
setIsModalOpen(true);
|
|
1453
|
+
}, [setSelectedClaimType]);
|
|
1454
|
+
const handleEdit = useCallback7(
|
|
1455
|
+
async (id) => {
|
|
1456
|
+
const result = await getClaimTypeById(id);
|
|
1457
|
+
if (result.success && selectedClaimType) {
|
|
1458
|
+
setFormState({
|
|
1459
|
+
name: selectedClaimType.name || "",
|
|
1460
|
+
required: selectedClaimType.required || false,
|
|
1461
|
+
regex: selectedClaimType.regex || "",
|
|
1462
|
+
regexDescription: selectedClaimType.regexDescription || "",
|
|
1463
|
+
description: selectedClaimType.description || "",
|
|
1464
|
+
valueType: selectedClaimType.valueType || 0
|
|
1465
|
+
});
|
|
1466
|
+
setIsModalOpen(true);
|
|
1467
|
+
}
|
|
1468
|
+
},
|
|
1469
|
+
[getClaimTypeById, selectedClaimType]
|
|
1470
|
+
);
|
|
1471
|
+
useEffect3(() => {
|
|
1472
|
+
if (selectedClaimType) {
|
|
1473
|
+
setFormState({
|
|
1474
|
+
name: selectedClaimType.name || "",
|
|
1475
|
+
required: selectedClaimType.required || false,
|
|
1476
|
+
regex: selectedClaimType.regex || "",
|
|
1477
|
+
regexDescription: selectedClaimType.regexDescription || "",
|
|
1478
|
+
description: selectedClaimType.description || "",
|
|
1479
|
+
valueType: selectedClaimType.valueType || 0
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
}, [selectedClaimType]);
|
|
1483
|
+
const handleDelete = useCallback7(
|
|
1484
|
+
async (id, name) => {
|
|
1485
|
+
const status = await confirmation.warn(
|
|
1486
|
+
t("AbpIdentity::ClaimTypeDeletionConfirmationMessage", name) || `Are you sure you want to delete the claim type '${name}'?`,
|
|
1487
|
+
t("AbpIdentity::AreYouSure")
|
|
1488
|
+
);
|
|
1489
|
+
if (status === Toaster3.Status.confirm) {
|
|
1490
|
+
const result = await deleteClaimType(id);
|
|
1491
|
+
if (result.success) {
|
|
1492
|
+
onClaimTypeDeleted?.(id);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
},
|
|
1496
|
+
[confirmation, t, deleteClaimType, onClaimTypeDeleted]
|
|
1497
|
+
);
|
|
1498
|
+
const handleSubmit = useCallback7(async () => {
|
|
1499
|
+
if (!formState.name.trim()) return;
|
|
1500
|
+
setIsSubmitting(true);
|
|
1501
|
+
const claimTypeData = {
|
|
1502
|
+
id: selectedClaimType?.id,
|
|
1503
|
+
name: formState.name.trim(),
|
|
1504
|
+
required: formState.required,
|
|
1505
|
+
isStatic: selectedClaimType?.isStatic || false,
|
|
1506
|
+
regex: formState.regex,
|
|
1507
|
+
regexDescription: formState.regexDescription,
|
|
1508
|
+
description: formState.description,
|
|
1509
|
+
valueType: formState.valueType
|
|
1510
|
+
};
|
|
1511
|
+
let result;
|
|
1512
|
+
if (selectedClaimType?.id) {
|
|
1513
|
+
result = await updateClaimType(claimTypeData);
|
|
1514
|
+
if (result.success) {
|
|
1515
|
+
onClaimTypeUpdated?.(claimTypeData);
|
|
1516
|
+
}
|
|
1517
|
+
} else {
|
|
1518
|
+
result = await createClaimType(claimTypeData);
|
|
1519
|
+
if (result.success) {
|
|
1520
|
+
onClaimTypeCreated?.(claimTypeData);
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
setIsSubmitting(false);
|
|
1524
|
+
if (result.success) {
|
|
1525
|
+
setIsModalOpen(false);
|
|
1526
|
+
setFormState(DEFAULT_FORM_STATE3);
|
|
1527
|
+
setSelectedClaimType(null);
|
|
1528
|
+
}
|
|
1529
|
+
}, [formState, selectedClaimType, updateClaimType, createClaimType, onClaimTypeCreated, onClaimTypeUpdated, setSelectedClaimType]);
|
|
1530
|
+
const handleModalClose = useCallback7(() => {
|
|
1531
|
+
setIsModalOpen(false);
|
|
1532
|
+
setFormState(DEFAULT_FORM_STATE3);
|
|
1533
|
+
setSelectedClaimType(null);
|
|
1534
|
+
}, [setSelectedClaimType]);
|
|
1535
|
+
const handleInputChange = useCallback7(
|
|
1536
|
+
(field, value) => {
|
|
1537
|
+
setFormState((prev) => ({ ...prev, [field]: value }));
|
|
1538
|
+
},
|
|
1539
|
+
[]
|
|
1540
|
+
);
|
|
1541
|
+
return /* @__PURE__ */ jsxs3(Box3, { id: "identity-claims-wrapper", className: "card", p: 4, children: [
|
|
1542
|
+
/* @__PURE__ */ jsxs3(Flex3, { justify: "space-between", align: "center", mb: 4, children: [
|
|
1543
|
+
/* @__PURE__ */ jsx3(Text3, { fontSize: "xl", fontWeight: "bold", children: t("AbpIdentity::ClaimTypes") || "Claim Types" }),
|
|
1544
|
+
/* @__PURE__ */ jsx3(Button3, { colorPalette: "blue", onClick: handleAdd, children: t("AbpIdentity::NewClaimType") || "New Claim Type" })
|
|
1545
|
+
] }),
|
|
1546
|
+
/* @__PURE__ */ jsx3(Box3, { mb: 4, children: /* @__PURE__ */ jsx3(
|
|
1547
|
+
Input3,
|
|
1548
|
+
{
|
|
1549
|
+
placeholder: t("AbpIdentity::Search"),
|
|
1550
|
+
value: searchTerm,
|
|
1551
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
1552
|
+
maxW: "300px"
|
|
1553
|
+
}
|
|
1554
|
+
) }),
|
|
1555
|
+
error && /* @__PURE__ */ jsx3(Alert3, { status: "error", mb: 4, children: error }),
|
|
1556
|
+
isLoading && claimTypes.length === 0 && /* @__PURE__ */ jsx3(Flex3, { justify: "center", py: 8, children: /* @__PURE__ */ jsx3(Spinner3, { size: "lg" }) }),
|
|
1557
|
+
claimTypes.length > 0 && /* @__PURE__ */ jsxs3(Table3.Root, { variant: "outline", children: [
|
|
1558
|
+
/* @__PURE__ */ jsx3(Table3.Header, { children: /* @__PURE__ */ jsxs3(Table3.Row, { children: [
|
|
1559
|
+
/* @__PURE__ */ jsx3(Table3.ColumnHeader, { children: t("AbpIdentity::Actions") }),
|
|
1560
|
+
/* @__PURE__ */ jsx3(Table3.ColumnHeader, { children: t("AbpIdentity::ClaimTypeName") || "Name" }),
|
|
1561
|
+
/* @__PURE__ */ jsx3(Table3.ColumnHeader, { children: t("AbpIdentity::ValueType") || "Value Type" }),
|
|
1562
|
+
/* @__PURE__ */ jsx3(Table3.ColumnHeader, { children: t("AbpIdentity::Description") || "Description" })
|
|
1563
|
+
] }) }),
|
|
1564
|
+
/* @__PURE__ */ jsx3(Table3.Body, { children: filteredClaimTypes.map((claimType) => /* @__PURE__ */ jsxs3(Table3.Row, { children: [
|
|
1565
|
+
/* @__PURE__ */ jsx3(Table3.Cell, { children: /* @__PURE__ */ jsxs3(Menu3.Root, { children: [
|
|
1566
|
+
/* @__PURE__ */ jsx3(Menu3.Trigger, { asChild: true, children: /* @__PURE__ */ jsx3(Button3, { size: "sm", colorPalette: "blue", children: t("AbpIdentity::Actions") }) }),
|
|
1567
|
+
/* @__PURE__ */ jsx3(Menu3.Positioner, { children: /* @__PURE__ */ jsxs3(Menu3.Content, { children: [
|
|
1568
|
+
/* @__PURE__ */ jsx3(Menu3.Item, { value: "edit", onClick: () => handleEdit(claimType.id), children: t("AbpIdentity::Edit") }),
|
|
1569
|
+
!claimType.isStatic && /* @__PURE__ */ jsx3(
|
|
1570
|
+
Menu3.Item,
|
|
1571
|
+
{
|
|
1572
|
+
value: "delete",
|
|
1573
|
+
color: "red.500",
|
|
1574
|
+
onClick: () => handleDelete(claimType.id, claimType.name),
|
|
1575
|
+
children: t("AbpIdentity::Delete")
|
|
1576
|
+
}
|
|
1577
|
+
)
|
|
1578
|
+
] }) })
|
|
1579
|
+
] }) }),
|
|
1580
|
+
/* @__PURE__ */ jsx3(Table3.Cell, { children: claimType.name }),
|
|
1581
|
+
/* @__PURE__ */ jsx3(Table3.Cell, { children: getValueTypeName(claimType.valueType) }),
|
|
1582
|
+
/* @__PURE__ */ jsx3(Table3.Cell, { children: claimType.description })
|
|
1583
|
+
] }, claimType.id)) })
|
|
1584
|
+
] }),
|
|
1585
|
+
!isLoading && claimTypes.length === 0 && /* @__PURE__ */ jsx3(Text3, { textAlign: "center", color: "gray.500", py: 8, children: t("AbpIdentity::NoClaimTypesFound") || "No claim types found" }),
|
|
1586
|
+
/* @__PURE__ */ jsx3(
|
|
1587
|
+
Modal3,
|
|
1588
|
+
{
|
|
1589
|
+
visible: isModalOpen,
|
|
1590
|
+
onVisibleChange: setIsModalOpen,
|
|
1591
|
+
header: selectedClaimType?.id ? t("AbpIdentity::Edit") : t("AbpIdentity::NewClaimType") || "New Claim Type",
|
|
1592
|
+
footer: /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
1593
|
+
/* @__PURE__ */ jsx3(Button3, { variant: "outline", onClick: handleModalClose, disabled: isSubmitting, children: t("AbpIdentity::Cancel") }),
|
|
1594
|
+
/* @__PURE__ */ jsx3(
|
|
1595
|
+
Button3,
|
|
1596
|
+
{
|
|
1597
|
+
colorPalette: "blue",
|
|
1598
|
+
onClick: handleSubmit,
|
|
1599
|
+
loading: isSubmitting,
|
|
1600
|
+
disabled: !formState.name.trim(),
|
|
1601
|
+
children: t("AbpIdentity::Save")
|
|
1602
|
+
}
|
|
1603
|
+
)
|
|
1604
|
+
] }),
|
|
1605
|
+
children: /* @__PURE__ */ jsxs3(VStack3, { gap: 4, align: "stretch", children: [
|
|
1606
|
+
/* @__PURE__ */ jsx3(FormField3, { label: t("AbpIdentity::ClaimTypeName") || "Name", required: true, children: /* @__PURE__ */ jsx3(
|
|
1607
|
+
Input3,
|
|
1608
|
+
{
|
|
1609
|
+
value: formState.name,
|
|
1610
|
+
onChange: (e) => handleInputChange("name", e.target.value),
|
|
1611
|
+
maxLength: 256,
|
|
1612
|
+
placeholder: t("AbpIdentity::ClaimTypeName") || "Name",
|
|
1613
|
+
disabled: selectedClaimType?.isStatic
|
|
1614
|
+
}
|
|
1615
|
+
) }),
|
|
1616
|
+
/* @__PURE__ */ jsx3(FormField3, { label: t("AbpIdentity::ValueType") || "Value Type", children: /* @__PURE__ */ jsx3(NativeSelectRoot, { children: /* @__PURE__ */ jsx3(
|
|
1617
|
+
NativeSelectField,
|
|
1618
|
+
{
|
|
1619
|
+
value: formState.valueType,
|
|
1620
|
+
onChange: (e) => handleInputChange("valueType", parseInt(e.target.value, 10)),
|
|
1621
|
+
children: VALUE_TYPE_OPTIONS.map((option) => /* @__PURE__ */ jsx3("option", { value: option.value, children: option.label }, option.value))
|
|
1622
|
+
}
|
|
1623
|
+
) }) }),
|
|
1624
|
+
/* @__PURE__ */ jsx3(FormField3, { label: t("AbpIdentity::Description") || "Description", children: /* @__PURE__ */ jsx3(
|
|
1625
|
+
Textarea,
|
|
1626
|
+
{
|
|
1627
|
+
value: formState.description,
|
|
1628
|
+
onChange: (e) => handleInputChange("description", e.target.value),
|
|
1629
|
+
placeholder: t("AbpIdentity::Description") || "Description",
|
|
1630
|
+
rows: 2
|
|
1631
|
+
}
|
|
1632
|
+
) }),
|
|
1633
|
+
/* @__PURE__ */ jsx3(FormField3, { label: t("AbpIdentity::Regex") || "Regex", children: /* @__PURE__ */ jsx3(
|
|
1634
|
+
Input3,
|
|
1635
|
+
{
|
|
1636
|
+
value: formState.regex,
|
|
1637
|
+
onChange: (e) => handleInputChange("regex", e.target.value),
|
|
1638
|
+
placeholder: t("AbpIdentity::Regex") || "Regex pattern"
|
|
1639
|
+
}
|
|
1640
|
+
) }),
|
|
1641
|
+
/* @__PURE__ */ jsx3(FormField3, { label: t("AbpIdentity::RegexDescription") || "Regex Description", children: /* @__PURE__ */ jsx3(
|
|
1642
|
+
Input3,
|
|
1643
|
+
{
|
|
1644
|
+
value: formState.regexDescription,
|
|
1645
|
+
onChange: (e) => handleInputChange("regexDescription", e.target.value),
|
|
1646
|
+
placeholder: t("AbpIdentity::RegexDescription") || "Regex description"
|
|
1647
|
+
}
|
|
1648
|
+
) })
|
|
1649
|
+
] })
|
|
1650
|
+
}
|
|
1651
|
+
)
|
|
1652
|
+
] });
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
// src/components/Claims/ClaimModal.tsx
|
|
1656
|
+
import { useEffect as useEffect4, useState as useState7, useCallback as useCallback8 } from "react";
|
|
1657
|
+
import { useLocalization as useLocalization4 } from "@abpjs/core";
|
|
1658
|
+
import { Modal as Modal4, Button as Button4, FormField as FormField4 } from "@abpjs/theme-shared";
|
|
1659
|
+
import {
|
|
1660
|
+
Box as Box4,
|
|
1661
|
+
Flex as Flex4,
|
|
1662
|
+
Input as Input4,
|
|
1663
|
+
VStack as VStack4,
|
|
1664
|
+
HStack,
|
|
1665
|
+
IconButton,
|
|
1666
|
+
Text as Text4
|
|
1667
|
+
} from "@chakra-ui/react";
|
|
1668
|
+
import { NativeSelectRoot as NativeSelectRoot2, NativeSelectField as NativeSelectField2 } from "@chakra-ui/react";
|
|
1669
|
+
import { LuTrash, LuPlus } from "react-icons/lu";
|
|
1670
|
+
import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1671
|
+
function ClaimModal({
|
|
1672
|
+
visible,
|
|
1673
|
+
onVisibleChange,
|
|
1674
|
+
subjectId,
|
|
1675
|
+
subjectType,
|
|
1676
|
+
onSaved
|
|
1677
|
+
}) {
|
|
1678
|
+
const { t } = useLocalization4();
|
|
1679
|
+
const {
|
|
1680
|
+
claimTypeNames,
|
|
1681
|
+
fetchClaimTypeNames,
|
|
1682
|
+
getClaims,
|
|
1683
|
+
updateClaims,
|
|
1684
|
+
isLoading
|
|
1685
|
+
} = useClaims();
|
|
1686
|
+
const [subjectClaims, setSubjectClaims] = useState7([]);
|
|
1687
|
+
const [newClaimType, setNewClaimType] = useState7("");
|
|
1688
|
+
const [newClaimValue, setNewClaimValue] = useState7("");
|
|
1689
|
+
const [isSaving, setIsSaving] = useState7(false);
|
|
1690
|
+
const initModal = useCallback8(async () => {
|
|
1691
|
+
if (!visible || !subjectId) return;
|
|
1692
|
+
await fetchClaimTypeNames();
|
|
1693
|
+
const claims = await getClaims(subjectId, subjectType);
|
|
1694
|
+
setSubjectClaims(claims);
|
|
1695
|
+
}, [visible, subjectId, subjectType, fetchClaimTypeNames, getClaims]);
|
|
1696
|
+
useEffect4(() => {
|
|
1697
|
+
if (visible) {
|
|
1698
|
+
initModal();
|
|
1699
|
+
} else {
|
|
1700
|
+
setSubjectClaims([]);
|
|
1701
|
+
setNewClaimType("");
|
|
1702
|
+
setNewClaimValue("");
|
|
1703
|
+
}
|
|
1704
|
+
}, [visible, initModal]);
|
|
1705
|
+
const handleAddClaim = useCallback8(() => {
|
|
1706
|
+
if (!newClaimType.trim() || !newClaimValue.trim()) return;
|
|
1707
|
+
const newClaim = {
|
|
1708
|
+
claimType: newClaimType.trim(),
|
|
1709
|
+
claimValue: newClaimValue.trim(),
|
|
1710
|
+
...subjectType === "users" ? { userId: subjectId } : { roleId: subjectId }
|
|
1711
|
+
};
|
|
1712
|
+
setSubjectClaims((prev) => [...prev, newClaim]);
|
|
1713
|
+
setNewClaimType("");
|
|
1714
|
+
setNewClaimValue("");
|
|
1715
|
+
}, [newClaimType, newClaimValue, subjectId, subjectType]);
|
|
1716
|
+
const handleRemoveClaim = useCallback8((index) => {
|
|
1717
|
+
setSubjectClaims((prev) => prev.filter((_, i) => i !== index));
|
|
1718
|
+
}, []);
|
|
1719
|
+
const handleSave = useCallback8(async () => {
|
|
1720
|
+
setIsSaving(true);
|
|
1721
|
+
const result = await updateClaims(subjectId, subjectType, subjectClaims);
|
|
1722
|
+
setIsSaving(false);
|
|
1723
|
+
if (result.success) {
|
|
1724
|
+
onSaved?.();
|
|
1725
|
+
onVisibleChange(false);
|
|
1726
|
+
}
|
|
1727
|
+
}, [subjectId, subjectType, subjectClaims, updateClaims, onSaved, onVisibleChange]);
|
|
1728
|
+
const handleClose = useCallback8(() => {
|
|
1729
|
+
onVisibleChange(false);
|
|
1730
|
+
}, [onVisibleChange]);
|
|
1731
|
+
const modalTitle = subjectType === "users" ? t("AbpIdentity::UserClaims") || "User Claims" : t("AbpIdentity::RoleClaims") || "Role Claims";
|
|
1732
|
+
return /* @__PURE__ */ jsx4(
|
|
1733
|
+
Modal4,
|
|
1734
|
+
{
|
|
1735
|
+
visible,
|
|
1736
|
+
onVisibleChange,
|
|
1737
|
+
header: modalTitle,
|
|
1738
|
+
size: "lg",
|
|
1739
|
+
footer: /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1740
|
+
/* @__PURE__ */ jsx4(Button4, { variant: "outline", onClick: handleClose, disabled: isSaving, children: t("AbpIdentity::Cancel") }),
|
|
1741
|
+
/* @__PURE__ */ jsx4(
|
|
1742
|
+
Button4,
|
|
1743
|
+
{
|
|
1744
|
+
colorPalette: "blue",
|
|
1745
|
+
onClick: handleSave,
|
|
1746
|
+
loading: isSaving,
|
|
1747
|
+
children: t("AbpIdentity::Save")
|
|
1748
|
+
}
|
|
1749
|
+
)
|
|
1750
|
+
] }),
|
|
1751
|
+
children: /* @__PURE__ */ jsxs4(VStack4, { gap: 4, align: "stretch", children: [
|
|
1752
|
+
/* @__PURE__ */ jsxs4(Box4, { borderWidth: "1px", borderRadius: "md", p: 4, children: [
|
|
1753
|
+
/* @__PURE__ */ jsx4(Text4, { fontWeight: "semibold", mb: 3, children: t("AbpIdentity::AddNewClaim") || "Add New Claim" }),
|
|
1754
|
+
/* @__PURE__ */ jsxs4(HStack, { gap: 3, align: "flex-end", children: [
|
|
1755
|
+
/* @__PURE__ */ jsx4(Box4, { flex: 1, children: /* @__PURE__ */ jsx4(FormField4, { label: t("AbpIdentity::ClaimType") || "Claim Type", children: claimTypeNames.length > 0 ? /* @__PURE__ */ jsx4(NativeSelectRoot2, { children: /* @__PURE__ */ jsxs4(
|
|
1756
|
+
NativeSelectField2,
|
|
1757
|
+
{
|
|
1758
|
+
value: newClaimType,
|
|
1759
|
+
onChange: (e) => setNewClaimType(e.target.value),
|
|
1760
|
+
placeholder: t("AbpIdentity::SelectClaimType") || "Select claim type",
|
|
1761
|
+
children: [
|
|
1762
|
+
/* @__PURE__ */ jsx4("option", { value: "", children: t("AbpIdentity::SelectClaimType") || "Select claim type" }),
|
|
1763
|
+
claimTypeNames.map((ct) => /* @__PURE__ */ jsx4("option", { value: ct.name, children: ct.name }, ct.name))
|
|
1764
|
+
]
|
|
1765
|
+
}
|
|
1766
|
+
) }) : /* @__PURE__ */ jsx4(
|
|
1767
|
+
Input4,
|
|
1768
|
+
{
|
|
1769
|
+
value: newClaimType,
|
|
1770
|
+
onChange: (e) => setNewClaimType(e.target.value),
|
|
1771
|
+
placeholder: t("AbpIdentity::ClaimType") || "Claim type"
|
|
1772
|
+
}
|
|
1773
|
+
) }) }),
|
|
1774
|
+
/* @__PURE__ */ jsx4(Box4, { flex: 1, children: /* @__PURE__ */ jsx4(FormField4, { label: t("AbpIdentity::ClaimValue") || "Claim Value", children: /* @__PURE__ */ jsx4(
|
|
1775
|
+
Input4,
|
|
1776
|
+
{
|
|
1777
|
+
value: newClaimValue,
|
|
1778
|
+
onChange: (e) => setNewClaimValue(e.target.value),
|
|
1779
|
+
placeholder: t("AbpIdentity::ClaimValue") || "Claim value"
|
|
1780
|
+
}
|
|
1781
|
+
) }) }),
|
|
1782
|
+
/* @__PURE__ */ jsx4(
|
|
1783
|
+
IconButton,
|
|
1784
|
+
{
|
|
1785
|
+
"aria-label": t("AbpIdentity::Add") || "Add",
|
|
1786
|
+
colorPalette: "blue",
|
|
1787
|
+
onClick: handleAddClaim,
|
|
1788
|
+
disabled: !newClaimType.trim() || !newClaimValue.trim(),
|
|
1789
|
+
children: /* @__PURE__ */ jsx4(LuPlus, {})
|
|
1790
|
+
}
|
|
1791
|
+
)
|
|
1792
|
+
] })
|
|
1793
|
+
] }),
|
|
1794
|
+
/* @__PURE__ */ jsxs4(Box4, { children: [
|
|
1795
|
+
/* @__PURE__ */ jsxs4(Text4, { fontWeight: "semibold", mb: 3, children: [
|
|
1796
|
+
t("AbpIdentity::CurrentClaims") || "Current Claims",
|
|
1797
|
+
" (",
|
|
1798
|
+
subjectClaims.length,
|
|
1799
|
+
")"
|
|
1800
|
+
] }),
|
|
1801
|
+
subjectClaims.length === 0 ? /* @__PURE__ */ jsx4(Text4, { color: "gray.500", textAlign: "center", py: 4, children: t("AbpIdentity::NoClaimsFound") || "No claims found" }) : /* @__PURE__ */ jsx4(VStack4, { gap: 2, align: "stretch", children: subjectClaims.map((claim, index) => /* @__PURE__ */ jsxs4(
|
|
1802
|
+
Flex4,
|
|
1803
|
+
{
|
|
1804
|
+
justify: "space-between",
|
|
1805
|
+
align: "center",
|
|
1806
|
+
p: 3,
|
|
1807
|
+
borderWidth: "1px",
|
|
1808
|
+
borderRadius: "md",
|
|
1809
|
+
children: [
|
|
1810
|
+
/* @__PURE__ */ jsxs4(Box4, { children: [
|
|
1811
|
+
/* @__PURE__ */ jsx4(Text4, { fontWeight: "medium", children: claim.claimType }),
|
|
1812
|
+
/* @__PURE__ */ jsx4(Text4, { fontSize: "sm", color: "gray.600", children: claim.claimValue })
|
|
1813
|
+
] }),
|
|
1814
|
+
/* @__PURE__ */ jsx4(
|
|
1815
|
+
IconButton,
|
|
1816
|
+
{
|
|
1817
|
+
"aria-label": t("AbpIdentity::Remove") || "Remove",
|
|
1818
|
+
colorPalette: "red",
|
|
1819
|
+
variant: "ghost",
|
|
1820
|
+
size: "sm",
|
|
1821
|
+
onClick: () => handleRemoveClaim(index),
|
|
1822
|
+
children: /* @__PURE__ */ jsx4(LuTrash, {})
|
|
1823
|
+
}
|
|
1824
|
+
)
|
|
1825
|
+
]
|
|
1826
|
+
},
|
|
1827
|
+
index
|
|
1828
|
+
)) })
|
|
1829
|
+
] }),
|
|
1830
|
+
isLoading && /* @__PURE__ */ jsx4(Text4, { textAlign: "center", color: "gray.500", children: t("AbpUi::Loading") || "Loading..." })
|
|
1831
|
+
] })
|
|
1832
|
+
}
|
|
1833
|
+
);
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
// src/constants/routes.ts
|
|
1837
|
+
import { eLayoutType } from "@abpjs/core";
|
|
1838
|
+
var IDENTITY_ROUTES = {
|
|
1839
|
+
routes: [
|
|
1840
|
+
{
|
|
1841
|
+
name: "AbpUiNavigation::Menu:Administration",
|
|
1842
|
+
path: "",
|
|
1843
|
+
order: 1,
|
|
1844
|
+
wrapper: true
|
|
1845
|
+
},
|
|
1846
|
+
{
|
|
1847
|
+
name: "AbpIdentity::Menu:IdentityManagement",
|
|
1848
|
+
path: "identity",
|
|
1849
|
+
order: 1,
|
|
1850
|
+
parentName: "AbpUiNavigation::Menu:Administration",
|
|
1851
|
+
layout: eLayoutType.application,
|
|
1852
|
+
children: [
|
|
1853
|
+
{
|
|
1854
|
+
path: "roles",
|
|
1855
|
+
name: "AbpIdentity::Roles",
|
|
1856
|
+
order: 2,
|
|
1857
|
+
requiredPolicy: "AbpIdentity.Roles"
|
|
1858
|
+
},
|
|
1859
|
+
{
|
|
1860
|
+
path: "users",
|
|
1861
|
+
name: "AbpIdentity::Users",
|
|
1862
|
+
order: 1,
|
|
1863
|
+
requiredPolicy: "AbpIdentity.Users"
|
|
1864
|
+
}
|
|
1865
|
+
]
|
|
1866
|
+
}
|
|
1867
|
+
]
|
|
1868
|
+
};
|
|
1869
|
+
var IDENTITY_ROUTE_PATHS = {
|
|
1870
|
+
/** Base path for identity module */
|
|
1871
|
+
BASE: "/identity",
|
|
1872
|
+
/** Roles management path */
|
|
1873
|
+
ROLES: "/identity/roles",
|
|
1874
|
+
/** Users management path */
|
|
1875
|
+
USERS: "/identity/users"
|
|
1876
|
+
};
|
|
1877
|
+
var IDENTITY_POLICIES = {
|
|
1878
|
+
/** Policy for roles management */
|
|
1879
|
+
ROLES: "AbpIdentity.Roles",
|
|
1880
|
+
/** Policy for users management */
|
|
1881
|
+
USERS: "AbpIdentity.Users",
|
|
1882
|
+
/** Policy for creating users */
|
|
1883
|
+
USERS_CREATE: "AbpIdentity.Users.Create",
|
|
1884
|
+
/** Policy for updating users */
|
|
1885
|
+
USERS_UPDATE: "AbpIdentity.Users.Update",
|
|
1886
|
+
/** Policy for deleting users */
|
|
1887
|
+
USERS_DELETE: "AbpIdentity.Users.Delete",
|
|
1888
|
+
/** Policy for creating roles */
|
|
1889
|
+
ROLES_CREATE: "AbpIdentity.Roles.Create",
|
|
1890
|
+
/** Policy for updating roles */
|
|
1891
|
+
ROLES_UPDATE: "AbpIdentity.Roles.Update",
|
|
1892
|
+
/** Policy for deleting roles */
|
|
1893
|
+
ROLES_DELETE: "AbpIdentity.Roles.Delete"
|
|
1894
|
+
};
|
|
1895
|
+
export {
|
|
1896
|
+
ClaimModal,
|
|
1897
|
+
ClaimsComponent,
|
|
1898
|
+
IDENTITY_POLICIES,
|
|
1899
|
+
IDENTITY_ROUTES,
|
|
1900
|
+
IDENTITY_ROUTE_PATHS,
|
|
1901
|
+
Identity,
|
|
1902
|
+
IdentityService,
|
|
1903
|
+
RolesComponent,
|
|
1904
|
+
UsersComponent,
|
|
1905
|
+
useClaims,
|
|
1906
|
+
useIdentity,
|
|
1907
|
+
useRoles,
|
|
1908
|
+
useUsers
|
|
1909
|
+
};
|