@deix/rossini-identity-management 5.1.3 → 5.2.1
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/lib/components/groups/GroupUsers.d.ts +1 -2
- package/lib/components/groups/GroupUsers.d.ts.map +1 -1
- package/lib/components/groups/GroupUsers.js +17 -10
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/types/users.d.ts +12 -0
- package/lib/types/users.d.ts.map +1 -1
- package/lib/utils/hooks/users.d.ts +3 -2
- package/lib/utils/hooks/users.d.ts.map +1 -1
- package/lib/utils/hooks/users.js +38 -19
- package/package.json +2 -2
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import { Group } from '../../types/groups';
|
|
3
2
|
interface GroupUsersProps {
|
|
4
3
|
group: Group;
|
|
5
4
|
}
|
|
6
|
-
declare const GroupUsers: ({ group }: GroupUsersProps) =>
|
|
5
|
+
declare const GroupUsers: ({ group }: GroupUsersProps) => import("react").JSX.Element;
|
|
7
6
|
export default GroupUsers;
|
|
8
7
|
//# sourceMappingURL=GroupUsers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupUsers.d.ts","sourceRoot":"","sources":["../../../src/components/groups/GroupUsers.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GroupUsers.d.ts","sourceRoot":"","sources":["../../../src/components/groups/GroupUsers.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AA4B3C,UAAU,eAAe;IACvB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,QAAA,MAAM,UAAU,cAAe,eAAe,gCA2D7C,CAAC;eAEa,UAAU"}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Button } from '@mui/material';
|
|
3
2
|
import AddIcon from '@mui/icons-material/Add';
|
|
4
|
-
import {
|
|
5
|
-
import { useState } from 'react';
|
|
3
|
+
import { Box, Button } from '@mui/material';
|
|
6
4
|
import { useQueryClient } from '@tanstack/react-query';
|
|
7
|
-
import
|
|
8
|
-
import Table from '../tables/Table';
|
|
9
|
-
import { useGroupUsers } from '../../utils/hooks/groups';
|
|
5
|
+
import { useState } from 'react';
|
|
10
6
|
import groupsTranslations from '../../lang/groups';
|
|
11
7
|
import usersTranslations from '../../lang/users';
|
|
8
|
+
import { useGroupUsers } from '../../utils/hooks/groups';
|
|
12
9
|
import { useAPIClient } from '../../utils/hooks/useAPIClient';
|
|
10
|
+
import { useAddUserToGroup, useRemoveUserFromGroup, useUsers, } from '../../utils/hooks/users';
|
|
13
11
|
import useTranslate from '../../utils/hooks/useTranslate';
|
|
12
|
+
import AddItemDialog from '../AddItemDialog';
|
|
13
|
+
import Table from '../tables/Table';
|
|
14
14
|
const groupUsersTableColumns = [
|
|
15
15
|
{
|
|
16
16
|
field: 'username',
|
|
@@ -38,9 +38,16 @@ const GroupUsers = ({ group }) => {
|
|
|
38
38
|
if (value) {
|
|
39
39
|
addUserToGroup({ userId: value?.value, groupId: group.id });
|
|
40
40
|
}
|
|
41
|
-
}, title: groupsTranslations.addUser, options: users?.map((user) =>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
}, title: groupsTranslations.addUser, options: users?.map((user) => {
|
|
42
|
+
const fullName = [user.firstName, user.lastName]
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.join(' ');
|
|
45
|
+
return {
|
|
46
|
+
value: user.id,
|
|
47
|
+
label: fullName
|
|
48
|
+
? `${fullName} (${user.username})`
|
|
49
|
+
: user.username || '',
|
|
50
|
+
};
|
|
51
|
+
}) })] }));
|
|
45
52
|
};
|
|
46
53
|
export default GroupUsers;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { default as Users } from './components/users/Users';
|
|
2
2
|
export { default as Groups } from './components/groups/Groups';
|
|
3
|
-
export type { User, KeycloakQueryParams } from './types/users';
|
|
3
|
+
export type { User, KeycloakQueryParams, UserByIdResult, UseUsersByIdsOptions, } from './types/users';
|
|
4
4
|
export type { Group } from './types/groups';
|
|
5
5
|
export { default as SearchField } from './components/SearchField';
|
|
6
6
|
export { default as DeleteConfirmationDialog } from './components/DeleteConfirmationDialog';
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAC/D,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAC/D,YAAY,EACV,IAAI,EACJ,mBAAmB,EACnB,cAAc,EACd,oBAAoB,GACrB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AAC5F,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACtE,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,4BAA4B,CAAC"}
|
package/lib/types/users.d.ts
CHANGED
|
@@ -7,8 +7,20 @@ export interface User {
|
|
|
7
7
|
enabled?: boolean;
|
|
8
8
|
email?: string;
|
|
9
9
|
emailVerified?: boolean;
|
|
10
|
+
serviceAccountClientId?: string;
|
|
10
11
|
}
|
|
11
12
|
export interface KeycloakQueryParams {
|
|
12
13
|
briefRepresentation?: boolean;
|
|
13
14
|
}
|
|
15
|
+
export interface UserByIdResult {
|
|
16
|
+
data?: User;
|
|
17
|
+
isLoading: boolean;
|
|
18
|
+
isError: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface UseUsersByIdsOptions {
|
|
21
|
+
/** Milliseconds a cached user is considered fresh. Default: 60000. */
|
|
22
|
+
staleTime?: number;
|
|
23
|
+
/** Retries on error (true/false or a number). Default: false. */
|
|
24
|
+
retry?: boolean | number;
|
|
25
|
+
}
|
|
14
26
|
//# sourceMappingURL=users.d.ts.map
|
package/lib/types/users.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/types/users.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/types/users.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AASD,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { QueryClient, UseQueryResult } from '@tanstack/react-query';
|
|
2
2
|
import { AxiosInstance } from 'axios';
|
|
3
|
-
import { KeycloakQueryParams, User } from '../../types/users';
|
|
4
|
-
import { Group } from '../../types/groups';
|
|
5
3
|
import { UserFormFields } from '../../components/users/UserForm';
|
|
4
|
+
import { Group } from '../../types/groups';
|
|
5
|
+
import { KeycloakQueryParams, User, UserByIdResult, UseUsersByIdsOptions } from '../../types/users';
|
|
6
6
|
export declare const getUsers: (apiClient: AxiosInstance, username?: string, group?: string, offset?: number, limit?: number, params?: KeycloakQueryParams) => Promise<User[]>;
|
|
7
7
|
export declare const useUsers: (apiClient: AxiosInstance, group?: string, offset?: number, limit?: number, params?: KeycloakQueryParams) => UseQueryResult<User[] | undefined, Error>;
|
|
8
8
|
export declare const getUser: (id: string, apiClient: AxiosInstance) => Promise<User>;
|
|
9
9
|
export declare const useUser: (id: string, apiClient: AxiosInstance) => UseQueryResult<User | undefined, Error>;
|
|
10
|
+
export declare const useUsersByIds: (apiClient: AxiosInstance, ids: (string | undefined)[], options?: UseUsersByIdsOptions) => UserByIdResult[];
|
|
10
11
|
export declare const addUser: ({ newUser, sendEmailOnCreation, apiClient, groups, }: {
|
|
11
12
|
newUser: User;
|
|
12
13
|
sendEmailOnCreation: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/utils/hooks/users.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/utils/hooks/users.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EAKX,cAAc,EACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAGtC,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEjE,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EACL,mBAAmB,EACnB,IAAI,EACJ,cAAc,EACd,oBAAoB,EACrB,MAAM,mBAAmB,CAAC;AAO3B,eAAO,MAAM,QAAQ,cACR,aAAa,aACb,MAAM,UACT,MAAM,WACN,MAAM,UACP,MAAM,WACJ,mBAAmB,oBA2B7B,CAAC;AAEF,eAAO,MAAM,QAAQ,cACR,aAAa,UAChB,MAAM,WACN,MAAM,UACP,MAAM,WACJ,mBAAmB,KAC3B,cAAc,CAAC,IAAI,EAAE,GAAG,SAAS,EAAE,KAAK,CAc1C,CAAC;AAGF,eAAO,MAAM,OAAO,OAAc,MAAM,aAAa,aAAa,kBAGjE,CAAC;AAEF,eAAO,MAAM,OAAO,OACd,MAAM,aACC,aAAa,KACvB,cAAc,CAAC,IAAI,GAAG,SAAS,EAAE,KAAK,CAMxC,CAAC;AAoBF,eAAO,MAAM,aAAa,cACb,aAAa,OACnB,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,YACjB,oBAAoB,KAC7B,cAAc,EAUb,CAAC;AAGL,eAAO,MAAM,OAAO,yDAKjB;IACD,OAAO,EAAE,IAAI,CAAC;IACd,mBAAmB,EAAE,OAAO,CAAC;IAC7B,SAAS,EAAE,aAAa,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,kBAWA,CAAC;AAEF,eAAO,MAAM,UAAU,gBACR,WAAW,aACb,aAAa;UAQd,cAAc;YACZ,MAAM,EAAE,GAAG,SAAS;WA6BjC,CAAC;AAiBF,eAAO,MAAM,aAAa,gBACX,WAAW,aACb,aAAa,kFA6BzB,CAAC;AAgBF,eAAO,MAAM,aAAa,gBACX,WAAW,aACb,aAAa,4GA6BzB,CAAC;AAcF,eAAO,MAAM,aAAa,OACpB,MAAM,GAAG,SAAS,aACX,aAAa,KACvB,cAAc,CAAC,KAAK,EAAE,GAAG,SAAS,EAAE,KAAK,CAM3C,CAAC;AAmBF,eAAO,MAAM,iBAAiB,gBACf,WAAW,aACb,aAAa;;;;YAIsB,MAAM;aAAW,MAAM;WA8BtE,CAAC;AAmBF,eAAO,MAAM,sBAAsB,gBACpB,WAAW,aACb,aAAa;;;;YAIsB,MAAM;aAAW,MAAM;WA8BtE,CAAC;AAkBF,eAAO,MAAM,0BAA0B,gBACxB,WAAW,aACb,aAAa;;0BAoBzB,CAAC;AAEF,eAAO,MAAM,aAAa,cACb,aAAa,aACb,MAAM,UACT,MAAM,oBAmBf,CAAC;AAEF,eAAO,MAAM,aAAa,cACb,aAAa,UAChB,MAAM,KACb,cAAc,CAAC,MAAM,GAAG,SAAS,EAAE,KAAK,CAM1C,CAAC"}
|
package/lib/utils/hooks/users.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { useMutation, useQuery, } from '@tanstack/react-query';
|
|
1
|
+
import { useMutation, useQueries, useQuery, } from '@tanstack/react-query';
|
|
2
2
|
import { enqueueSnackbar } from 'notistack';
|
|
3
3
|
import usersTranslations from '../../lang/users';
|
|
4
4
|
import useTranslate from './useTranslate';
|
|
5
|
+
const isServiceAccount = (u) => !!u.serviceAccountClientId || !!u.username?.startsWith('service-account-');
|
|
5
6
|
// Get list of users
|
|
6
7
|
export const getUsers = async (apiClient, username, group, offset = 0, limit = 1000, params) => {
|
|
7
8
|
const { briefRepresentation } = params ?? {};
|
|
@@ -10,26 +11,20 @@ export const getUsers = async (apiClient, username, group, offset = 0, limit = 1
|
|
|
10
11
|
const { data: groupData } = await apiClient.get(`/groups`, {
|
|
11
12
|
params: { max: 1, search: group, exact: 'true' },
|
|
12
13
|
});
|
|
13
|
-
if (groupData.length
|
|
14
|
-
const { data } = await apiClient.get(`/groups/${groupData[0].id}/members`, { params: { max: limit, first: offset, ...extraParams } });
|
|
15
|
-
return data;
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
14
|
+
if (groupData.length !== 1)
|
|
18
15
|
return [];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
else {
|
|
22
|
-
const { data } = await apiClient.get(`/users`, {
|
|
23
|
-
params: {
|
|
24
|
-
max: limit,
|
|
25
|
-
first: offset,
|
|
26
|
-
username,
|
|
27
|
-
exact: 'true',
|
|
28
|
-
...extraParams,
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
return data;
|
|
16
|
+
const { data } = await apiClient.get(`/groups/${groupData[0].id}/members`, { params: { max: limit, first: offset, ...extraParams } });
|
|
17
|
+
return data.filter((u) => !isServiceAccount(u));
|
|
32
18
|
}
|
|
19
|
+
const { data } = await apiClient.get(`/users`, {
|
|
20
|
+
params: {
|
|
21
|
+
max: limit,
|
|
22
|
+
first: offset,
|
|
23
|
+
...(username ? { username, exact: 'true' } : {}),
|
|
24
|
+
...extraParams,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
return data;
|
|
33
28
|
};
|
|
34
29
|
export const useUsers = (apiClient, group, offset = 0, limit = 1000, params) => {
|
|
35
30
|
return useQuery({
|
|
@@ -58,6 +53,30 @@ export const useUser = (id, apiClient) => {
|
|
|
58
53
|
staleTime: 0,
|
|
59
54
|
});
|
|
60
55
|
};
|
|
56
|
+
// Get multiple users by id
|
|
57
|
+
// Defined OUTSIDE the hook: its identity must be stable, otherwise React Query
|
|
58
|
+
// recomputes the combined result on every render and loses structural sharing.
|
|
59
|
+
// Without combine, useQueries returns a new array on every render.
|
|
60
|
+
const combineUsers = (results) => results.map((r) => ({
|
|
61
|
+
data: r.data,
|
|
62
|
+
isLoading: r.isLoading,
|
|
63
|
+
isError: r.isError,
|
|
64
|
+
}));
|
|
65
|
+
// Loads several Keycloak users with one GET /users/{id} each.
|
|
66
|
+
// useUser cannot be used here because hooks cannot be called in a loop.
|
|
67
|
+
// It uses the SAME queryKey as useUser (['user', id]), so the cache is shared with useUser.
|
|
68
|
+
// Results are in the same order as ids; an undefined id triggers no request.
|
|
69
|
+
// Each result is a reduced state (see UserByIdResult), not the full UseQueryResult.
|
|
70
|
+
export const useUsersByIds = (apiClient, ids, options) => useQueries({
|
|
71
|
+
queries: ids.map((id) => ({
|
|
72
|
+
queryKey: ['user', id],
|
|
73
|
+
queryFn: () => getUser(id, apiClient),
|
|
74
|
+
enabled: !!id,
|
|
75
|
+
staleTime: options?.staleTime ?? 60 * 1000,
|
|
76
|
+
retry: options?.retry ?? false,
|
|
77
|
+
})),
|
|
78
|
+
combine: combineUsers,
|
|
79
|
+
});
|
|
61
80
|
// Add user
|
|
62
81
|
export const addUser = async ({ newUser, sendEmailOnCreation, apiClient, groups, }) => {
|
|
63
82
|
await apiClient.post(`/users`, { ...newUser, groups });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deix/rossini-identity-management",
|
|
3
|
-
"version": "5.1
|
|
3
|
+
"version": "5.2.1",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"eslint-plugin-prettier": "^5.5.6",
|
|
63
63
|
"eslint-plugin-storybook": "^10.6.0",
|
|
64
64
|
"json-server": "^1.0.0-beta.15",
|
|
65
|
-
"next": "~16.3
|
|
65
|
+
"next": "~16.4.3",
|
|
66
66
|
"react": "^19.3.0",
|
|
67
67
|
"react-dom": "19.3.0",
|
|
68
68
|
"remark-mdx": "^3.0.0",
|