@keycloakify/keycloak-account-ui 25.0.4-rc.7 → 26.0.0-rc.0

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.
Files changed (193) hide show
  1. package/KcAccountUiLoader.d.ts +1 -0
  2. package/KcAccountUiLoader.js +2 -1
  3. package/KcAccountUiLoader.js.map +1 -1
  4. package/README.md +19 -19
  5. package/account-security/AccountRow.js +5 -4
  6. package/account-security/AccountRow.js.map +1 -1
  7. package/account-security/DeviceActivity.js +5 -4
  8. package/account-security/DeviceActivity.js.map +1 -1
  9. package/account-security/LinkedAccounts.js +24 -9
  10. package/account-security/LinkedAccounts.js.map +1 -1
  11. package/account-security/LinkedAccountsToolbar.d.ts +12 -0
  12. package/account-security/LinkedAccountsToolbar.js +24 -0
  13. package/account-security/LinkedAccountsToolbar.js.map +1 -0
  14. package/account-security/SigningIn.js +1 -1
  15. package/account-security/SigningIn.js.map +1 -1
  16. package/api/methods.d.ts +7 -1
  17. package/api/methods.js +9 -2
  18. package/api/methods.js.map +1 -1
  19. package/api/parse-links.js +3 -3
  20. package/api/parse-links.js.map +1 -1
  21. package/api/parse-response.d.ts +2 -0
  22. package/api/parse-response.js +11 -15
  23. package/api/parse-response.js.map +1 -1
  24. package/api/request.js +1 -1
  25. package/api/request.js.map +1 -1
  26. package/api.js +1 -7
  27. package/api.js.map +1 -1
  28. package/applications/Applications.js +5 -4
  29. package/applications/Applications.js.map +1 -1
  30. package/environment.d.ts +1 -0
  31. package/environment.js.map +1 -1
  32. package/messages/messages_ca.properties +105 -12
  33. package/messages/messages_de.properties +23 -1
  34. package/messages/messages_en.properties +16 -1
  35. package/messages/messages_es.properties +1 -1
  36. package/messages/messages_fr.properties +64 -19
  37. package/messages/messages_it.properties +3 -0
  38. package/messages/messages_ka.properties +15 -0
  39. package/messages/messages_nl.properties +2 -0
  40. package/organizations/Organizations.d.ts +2 -0
  41. package/organizations/Organizations.js +19 -0
  42. package/organizations/Organizations.js.map +1 -0
  43. package/package.json +89 -29
  44. package/personal-info/PersonalInfo.js +11 -9
  45. package/personal-info/PersonalInfo.js.map +1 -1
  46. package/public/content.d.ts +4 -0
  47. package/public/content.js +5 -0
  48. package/public/content.js.map +1 -1
  49. package/resources/EditTheResource.js +4 -3
  50. package/resources/EditTheResource.js.map +1 -1
  51. package/resources/PermissionRequest.js +4 -3
  52. package/resources/PermissionRequest.js.map +1 -1
  53. package/resources/ResourcesTab.js +4 -3
  54. package/resources/ResourcesTab.js.map +1 -1
  55. package/resources/ShareTheResource.js +4 -3
  56. package/resources/ShareTheResource.js.map +1 -1
  57. package/root/Header.js +1 -1
  58. package/root/Header.js.map +1 -1
  59. package/root/PageNav.js +1 -1
  60. package/root/PageNav.js.map +1 -1
  61. package/routes.d.ts +1 -0
  62. package/routes.js +6 -0
  63. package/routes.js.map +1 -1
  64. package/src/KcAccountUiLoader.tsx +2 -0
  65. package/src/account-security/AccountRow.tsx +6 -8
  66. package/src/account-security/DeviceActivity.tsx +10 -9
  67. package/src/account-security/LinkedAccounts.tsx +107 -30
  68. package/src/account-security/LinkedAccountsToolbar.tsx +88 -0
  69. package/src/account-security/SigningIn.tsx +1 -1
  70. package/src/api/methods.ts +22 -2
  71. package/src/api/parse-links.ts +3 -3
  72. package/src/api/parse-response.ts +22 -23
  73. package/src/api/request.ts +1 -1
  74. package/src/api.ts +1 -7
  75. package/src/applications/Applications.tsx +19 -11
  76. package/src/environment.ts +1 -0
  77. package/src/organizations/Organizations.tsx +48 -0
  78. package/src/personal-info/PersonalInfo.tsx +10 -8
  79. package/src/public/content.ts +5 -0
  80. package/src/resources/EditTheResource.tsx +8 -7
  81. package/src/resources/PermissionRequest.tsx +5 -3
  82. package/src/resources/ResourcesTab.tsx +8 -7
  83. package/src/resources/ShareTheResource.tsx +9 -8
  84. package/src/root/Header.tsx +0 -1
  85. package/src/root/PageNav.tsx +1 -1
  86. package/src/routes.tsx +7 -0
  87. package/src/ui-shared/alerts/AlertPanel.tsx +43 -0
  88. package/src/ui-shared/alerts/Alerts.tsx +48 -52
  89. package/src/ui-shared/context/environment.ts +1 -1
  90. package/src/ui-shared/controls/KeycloakSpinner.tsx +12 -0
  91. package/src/ui-shared/controls/OrganizationTable.tsx +122 -0
  92. package/src/ui-shared/controls/select-control/SingleSelectControl.tsx +3 -1
  93. package/src/ui-shared/controls/select-control/TypeaheadSelectControl.tsx +5 -3
  94. package/src/ui-shared/controls/table/KeycloakDataTable.tsx +597 -0
  95. package/src/ui-shared/controls/table/ListEmptyState.tsx +86 -0
  96. package/src/ui-shared/controls/table/PaginatingTableToolbar.tsx +106 -0
  97. package/src/ui-shared/controls/table/TableToolbar.tsx +92 -0
  98. package/src/ui-shared/main.ts +35 -1
  99. package/src/ui-shared/masthead/Masthead.tsx +64 -48
  100. package/src/ui-shared/select/SingleSelect.tsx +2 -0
  101. package/src/ui-shared/select/TypeaheadSelect.tsx +2 -0
  102. package/src/ui-shared/user-profile/LocaleSelector.tsx +1 -1
  103. package/src/ui-shared/user-profile/UserProfileFields.tsx +18 -21
  104. package/src/ui-shared/user-profile/UserProfileGroup.tsx +3 -2
  105. package/src/ui-shared/user-profile/utils.ts +12 -6
  106. package/src/ui-shared/utils/ErrorBoundary.tsx +77 -0
  107. package/src/ui-shared/utils/darkMode.ts +19 -0
  108. package/src/ui-shared/utils/errors.ts +55 -0
  109. package/src/ui-shared/utils/generateId.ts +1 -0
  110. package/src/ui-shared/utils/useFetch.ts +44 -0
  111. package/src/ui-shared/utils/useSetTimeout.ts +40 -0
  112. package/src/utils/useAccountAlerts.ts +28 -0
  113. package/src/utils/usePromise.ts +8 -3
  114. package/src/zKcContextLike.ts +1 -0
  115. package/ui-shared/alerts/AlertPanel.d.ts +6 -0
  116. package/ui-shared/alerts/AlertPanel.js +6 -0
  117. package/ui-shared/alerts/AlertPanel.js.map +1 -0
  118. package/ui-shared/alerts/Alerts.d.ts +2 -3
  119. package/ui-shared/alerts/Alerts.js +32 -22
  120. package/ui-shared/alerts/Alerts.js.map +1 -1
  121. package/ui-shared/context/environment.js +1 -1
  122. package/ui-shared/context/environment.js.map +1 -1
  123. package/ui-shared/controls/KeycloakSpinner.d.ts +1 -0
  124. package/ui-shared/controls/KeycloakSpinner.js +8 -0
  125. package/ui-shared/controls/KeycloakSpinner.js.map +1 -0
  126. package/ui-shared/controls/OrganizationTable.d.ts +16 -0
  127. package/ui-shared/controls/OrganizationTable.js +45 -0
  128. package/ui-shared/controls/OrganizationTable.js.map +1 -0
  129. package/ui-shared/controls/select-control/SingleSelectControl.js +3 -1
  130. package/ui-shared/controls/select-control/SingleSelectControl.js.map +1 -1
  131. package/ui-shared/controls/select-control/TypeaheadSelectControl.js +5 -3
  132. package/ui-shared/controls/select-control/TypeaheadSelectControl.js.map +1 -1
  133. package/ui-shared/controls/table/KeycloakDataTable.d.ts +64 -0
  134. package/ui-shared/controls/table/KeycloakDataTable.js +279 -0
  135. package/ui-shared/controls/table/KeycloakDataTable.js.map +1 -0
  136. package/ui-shared/controls/table/ListEmptyState.d.ts +20 -0
  137. package/ui-shared/controls/table/ListEmptyState.js +11 -0
  138. package/ui-shared/controls/table/ListEmptyState.js.map +1 -0
  139. package/ui-shared/controls/table/PaginatingTableToolbar.d.ts +21 -0
  140. package/ui-shared/controls/table/PaginatingTableToolbar.js +27 -0
  141. package/ui-shared/controls/table/PaginatingTableToolbar.js.map +1 -0
  142. package/ui-shared/controls/table/TableToolbar.d.ts +12 -0
  143. package/ui-shared/controls/table/TableToolbar.js +30 -0
  144. package/ui-shared/controls/table/TableToolbar.js.map +1 -0
  145. package/ui-shared/main.d.ts +15 -1
  146. package/ui-shared/main.js +13 -1
  147. package/ui-shared/main.js.map +1 -1
  148. package/ui-shared/masthead/Masthead.d.ts +4 -7
  149. package/ui-shared/masthead/Masthead.js +14 -14
  150. package/ui-shared/masthead/Masthead.js.map +1 -1
  151. package/ui-shared/select/SingleSelect.d.ts +1 -1
  152. package/ui-shared/select/SingleSelect.js +2 -2
  153. package/ui-shared/select/SingleSelect.js.map +1 -1
  154. package/ui-shared/select/TypeaheadSelect.d.ts +1 -1
  155. package/ui-shared/select/TypeaheadSelect.js +2 -2
  156. package/ui-shared/select/TypeaheadSelect.js.map +1 -1
  157. package/ui-shared/user-profile/LocaleSelector.js +1 -1
  158. package/ui-shared/user-profile/LocaleSelector.js.map +1 -1
  159. package/ui-shared/user-profile/UserProfileFields.d.ts +2 -4
  160. package/ui-shared/user-profile/UserProfileFields.js +0 -18
  161. package/ui-shared/user-profile/UserProfileFields.js.map +1 -1
  162. package/ui-shared/user-profile/UserProfileGroup.js.map +1 -1
  163. package/ui-shared/user-profile/utils.js +2 -2
  164. package/ui-shared/user-profile/utils.js.map +1 -1
  165. package/ui-shared/utils/ErrorBoundary.d.ts +26 -0
  166. package/ui-shared/utils/ErrorBoundary.js +29 -0
  167. package/ui-shared/utils/ErrorBoundary.js.map +1 -0
  168. package/ui-shared/utils/darkMode.d.ts +1 -0
  169. package/ui-shared/utils/darkMode.js +16 -0
  170. package/ui-shared/utils/darkMode.js.map +1 -0
  171. package/ui-shared/utils/errors.d.ts +4 -0
  172. package/ui-shared/utils/errors.js +42 -0
  173. package/ui-shared/utils/errors.js.map +1 -0
  174. package/ui-shared/utils/generateId.d.ts +1 -0
  175. package/ui-shared/utils/generateId.js +2 -0
  176. package/ui-shared/utils/generateId.js.map +1 -0
  177. package/ui-shared/utils/useFetch.d.ts +17 -0
  178. package/ui-shared/utils/useFetch.js +38 -0
  179. package/ui-shared/utils/useFetch.js.map +1 -0
  180. package/ui-shared/utils/useSetTimeout.d.ts +1 -0
  181. package/ui-shared/utils/useSetTimeout.js +32 -0
  182. package/ui-shared/utils/useSetTimeout.js.map +1 -0
  183. package/utils/useAccountAlerts.d.ts +4 -0
  184. package/utils/useAccountAlerts.js +19 -0
  185. package/utils/useAccountAlerts.js.map +1 -0
  186. package/utils/usePromise.js +7 -3
  187. package/utils/usePromise.js.map +1 -1
  188. package/zKcContextLike.js +1 -0
  189. package/zKcContextLike.js.map +1 -1
  190. package/src/utils/isRecord.ts +0 -2
  191. package/utils/isRecord.d.ts +0 -1
  192. package/utils/isRecord.js +0 -2
  193. package/utils/isRecord.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PageNav.js","sourceRoot":"","sources":["../src/root/PageNav.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PageNav.js","sourceRoot":"","sources":["../src/root/PageNav.tsx"],"names":[],"mappings":"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"}
package/routes.d.ts CHANGED
@@ -10,6 +10,7 @@ export type ContentComponentParams = {
10
10
  };
11
11
  export declare const ContentRoute: RouteObject;
12
12
  export declare const PersonalInfoRoute: IndexRouteObject;
13
+ export declare const OrganizationsRoute: RouteObject;
13
14
  export declare const Oid4VciRoute: RouteObject;
14
15
  export declare const RootRoute: RouteObject;
15
16
  export declare const routes: RouteObject[];
package/routes.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { lazy } from "react";
3
3
  import { environment } from "./environment";
4
+ import { Organizations } from "./organizations/Organizations";
4
5
  import { ErrorPage } from "./root/ErrorPage";
5
6
  import { Root } from "./root/Root";
6
7
  const DeviceActivity = lazy(() => import("./account-security/DeviceActivity"));
@@ -44,6 +45,10 @@ export const PersonalInfoRoute = {
44
45
  index: true,
45
46
  element: _jsx(PersonalInfo, {}),
46
47
  };
48
+ export const OrganizationsRoute = {
49
+ path: "organizations",
50
+ element: _jsx(Organizations, {}),
51
+ };
47
52
  export const Oid4VciRoute = {
48
53
  path: "oid4vci",
49
54
  element: _jsx(Oid4Vci, {}),
@@ -59,6 +64,7 @@ export const RootRoute = {
59
64
  SigningInRoute,
60
65
  ApplicationsRoute,
61
66
  GroupsRoute,
67
+ OrganizationsRoute,
62
68
  PersonalInfoRoute,
63
69
  ResourcesRoute,
64
70
  ContentRoute,
package/routes.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["src/routes.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["src/routes.tsx"],"names":[],"mappings":"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"}
@@ -36,6 +36,7 @@ export namespace KcContextLike {
36
36
  deleteAccountAllowed: boolean;
37
37
  updateEmailFeatureEnabled: boolean;
38
38
  updateEmailActionEnabled: boolean;
39
+ isViewOrganizationsEnabled?: boolean;
39
40
  };
40
41
 
41
42
  export type I18nApi = {
@@ -246,6 +247,7 @@ function init(
246
247
  isOid4VciEnabled: getIsKeycloak25AndUp(kcContext)
247
248
  ? kcContext.isOid4VciEnabled
248
249
  : false,
250
+ isViewOrganizationsEnabled: kcContext.isViewOrganizationsEnabled ?? false,
249
251
  },
250
252
  };
251
253
 
@@ -1,3 +1,4 @@
1
+ import { IconMapper, useEnvironment } from "@keycloakify/keycloak-account-ui/ui-shared";
1
2
  import {
2
3
  Button,
3
4
  DataListAction,
@@ -12,13 +13,10 @@ import {
12
13
  } from "@patternfly/react-core";
13
14
  import { LinkIcon, UnlinkIcon } from "@patternfly/react-icons";
14
15
  import { useTranslation } from "react-i18next";
15
- import {
16
- IconMapper,
17
- useAlerts,
18
- useEnvironment,
19
- } from "@keycloakify/keycloak-account-ui/ui-shared";
16
+
20
17
  import { linkAccount, unLinkAccount } from "@keycloakify/keycloak-account-ui/api/methods";
21
18
  import { LinkedAccountRepresentation } from "@keycloakify/keycloak-account-ui/api/representations";
19
+ import { useAccountAlerts } from "@keycloakify/keycloak-account-ui/utils/useAccountAlerts";
22
20
 
23
21
  type AccountRowProps = {
24
22
  account: LinkedAccountRepresentation;
@@ -33,7 +31,7 @@ export const AccountRow = ({
33
31
  }: AccountRowProps) => {
34
32
  const { t } = useTranslation();
35
33
  const context = useEnvironment();
36
- const { addAlert, addError } = useAlerts();
34
+ const { addAlert, addError } = useAccountAlerts();
37
35
 
38
36
  const unLink = async (account: LinkedAccountRepresentation) => {
39
37
  try {
@@ -41,7 +39,7 @@ export const AccountRow = ({
41
39
  addAlert(t("unLinkSuccess"));
42
40
  refresh();
43
41
  } catch (error) {
44
- addError(t("unLinkError", { error }).toString());
42
+ addError("unLinkError", error);
45
43
  }
46
44
  };
47
45
 
@@ -50,7 +48,7 @@ export const AccountRow = ({
50
48
  const { accountLinkUri } = await linkAccount(context, account);
51
49
  location.href = accountLinkUri;
52
50
  } catch (error) {
53
- addError(t("linkError", { error }).toString());
51
+ addError("linkError", error);
54
52
  }
55
53
  };
56
54
 
@@ -1,3 +1,8 @@
1
+ import {
2
+ ContinueCancelModal,
3
+ useEnvironment,
4
+ label,
5
+ } from "@keycloakify/keycloak-account-ui/ui-shared";
1
6
  import {
2
7
  Button,
3
8
  DataList,
@@ -23,11 +28,7 @@ import {
23
28
  } from "@patternfly/react-icons";
24
29
  import { useState } from "react";
25
30
  import { useTranslation } from "react-i18next";
26
- import {
27
- ContinueCancelModal,
28
- useAlerts,
29
- useEnvironment,
30
- } from "@keycloakify/keycloak-account-ui/ui-shared";
31
+
31
32
  import { deleteSession, getDevices } from "@keycloakify/keycloak-account-ui/api/methods";
32
33
  import {
33
34
  ClientRepresentation,
@@ -35,14 +36,14 @@ import {
35
36
  SessionRepresentation,
36
37
  } from "@keycloakify/keycloak-account-ui/api/representations";
37
38
  import { Page } from "@keycloakify/keycloak-account-ui/components/page/Page";
38
- import { TFuncKey } from "@keycloakify/keycloak-account-ui/i18n";
39
39
  import { formatDate } from "@keycloakify/keycloak-account-ui/utils/formatDate";
40
+ import { useAccountAlerts } from "@keycloakify/keycloak-account-ui/utils/useAccountAlerts";
40
41
  import { usePromise } from "@keycloakify/keycloak-account-ui/utils/usePromise";
41
42
 
42
43
  export const DeviceActivity = () => {
43
44
  const { t } = useTranslation();
44
45
  const context = useEnvironment();
45
- const { addAlert, addError } = useAlerts();
46
+ const { addAlert, addError } = useAccountAlerts();
46
47
 
47
48
  const [devices, setDevices] = useState<DeviceRepresentation[]>();
48
49
  const [key, setKey] = useState(0);
@@ -82,7 +83,7 @@ export const DeviceActivity = () => {
82
83
  );
83
84
  refresh();
84
85
  } catch (error) {
85
- addError(t("errorSignOutMessage", { error }).toString());
86
+ addError("errorSignOutMessage", error);
86
87
  }
87
88
  };
88
89
 
@@ -91,7 +92,7 @@ export const DeviceActivity = () => {
91
92
  clients.forEach((client, index) => {
92
93
  let clientName: string;
93
94
  if (client.clientName !== "") {
94
- clientName = t(client.clientName as TFuncKey);
95
+ clientName = label(t, client.clientName);
95
96
  } else {
96
97
  clientName = client.clientId;
97
98
  }
@@ -1,34 +1,49 @@
1
+ import { useEnvironment } from "@keycloakify/keycloak-account-ui/ui-shared";
1
2
  import { DataList, Stack, StackItem, Title } from "@patternfly/react-core";
2
- import { useMemo, useState } from "react";
3
+ import { useState } from "react";
3
4
  import { useTranslation } from "react-i18next";
4
- import { getLinkedAccounts } from "@keycloakify/keycloak-account-ui/api/methods";
5
+ import { getLinkedAccounts, LinkedAccountQueryParams } from "@keycloakify/keycloak-account-ui/api/methods";
5
6
  import { LinkedAccountRepresentation } from "@keycloakify/keycloak-account-ui/api/representations";
6
7
  import { EmptyRow } from "@keycloakify/keycloak-account-ui/components/datalist/EmptyRow";
7
8
  import { Page } from "@keycloakify/keycloak-account-ui/components/page/Page";
8
9
  import { usePromise } from "@keycloakify/keycloak-account-ui/utils/usePromise";
9
10
  import { AccountRow } from "@keycloakify/keycloak-account-ui/account-security/AccountRow";
10
- import { useEnvironment } from "@keycloakify/keycloak-account-ui/ui-shared";
11
+ import { LinkedAccountsToolbar } from "@keycloakify/keycloak-account-ui/account-security/LinkedAccountsToolbar";
11
12
 
12
13
  export const LinkedAccounts = () => {
13
14
  const { t } = useTranslation();
14
15
  const context = useEnvironment();
15
- const [accounts, setAccounts] = useState<LinkedAccountRepresentation[]>([]);
16
+ const [linkedAccounts, setLinkedAccounts] = useState<
17
+ LinkedAccountRepresentation[]
18
+ >([]);
19
+ const [unlinkedAccounts, setUninkedAccounts] = useState<
20
+ LinkedAccountRepresentation[]
21
+ >([]);
16
22
 
23
+ const [paramsUnlinked, setParamsUnlinked] =
24
+ useState<LinkedAccountQueryParams>({
25
+ first: 0,
26
+ max: 6,
27
+ linked: false,
28
+ });
29
+ const [paramsLinked, setParamsLinked] = useState<LinkedAccountQueryParams>({
30
+ first: 0,
31
+ max: 6,
32
+ linked: true,
33
+ });
17
34
  const [key, setKey] = useState(1);
18
35
  const refresh = () => setKey(key + 1);
19
36
 
20
- usePromise((signal) => getLinkedAccounts({ signal, context }), setAccounts, [
21
- key,
22
- ]);
23
-
24
- const linkedAccounts = useMemo(
25
- () => accounts.filter((account) => account.connected),
26
- [accounts],
37
+ usePromise(
38
+ (signal) => getLinkedAccounts({ signal, context }, paramsUnlinked),
39
+ setUninkedAccounts,
40
+ [paramsUnlinked, key],
27
41
  );
28
42
 
29
- const unLinkedAccounts = useMemo(
30
- () => accounts.filter((account) => !account.connected),
31
- [accounts],
43
+ usePromise(
44
+ (signal) => getLinkedAccounts({ signal, context }, paramsLinked),
45
+ setLinkedAccounts,
46
+ [paramsLinked, key],
32
47
  );
33
48
 
34
49
  return (
@@ -41,16 +56,47 @@ export const LinkedAccounts = () => {
41
56
  <Title headingLevel="h2" className="pf-v5-u-mb-lg" size="xl">
42
57
  {t("linkedLoginProviders")}
43
58
  </Title>
59
+ <LinkedAccountsToolbar
60
+ onFilter={(search) =>
61
+ setParamsLinked({ ...paramsLinked, first: 0, search })
62
+ }
63
+ count={linkedAccounts.length}
64
+ first={paramsLinked["first"]}
65
+ max={paramsLinked["max"]}
66
+ onNextClick={() => {
67
+ setParamsLinked({
68
+ ...paramsLinked,
69
+ first: paramsLinked.first + paramsLinked.max - 1,
70
+ });
71
+ }}
72
+ onPreviousClick={() =>
73
+ setParamsLinked({
74
+ ...paramsLinked,
75
+ first: paramsLinked.first - paramsLinked.max + 1,
76
+ })
77
+ }
78
+ onPerPageSelect={(first, max) =>
79
+ setParamsLinked({
80
+ ...paramsLinked,
81
+ first,
82
+ max,
83
+ })
84
+ }
85
+ hasNext={linkedAccounts.length > paramsLinked.max - 1}
86
+ />
44
87
  <DataList id="linked-idps" aria-label={t("linkedLoginProviders")}>
45
88
  {linkedAccounts.length > 0 ? (
46
- linkedAccounts.map((account) => (
47
- <AccountRow
48
- key={account.providerName}
49
- account={account}
50
- isLinked
51
- refresh={refresh}
52
- />
53
- ))
89
+ linkedAccounts.map(
90
+ (account, index) =>
91
+ index !== paramsLinked.max - 1 && (
92
+ <AccountRow
93
+ key={account.providerName}
94
+ account={account}
95
+ isLinked
96
+ refresh={refresh}
97
+ />
98
+ ),
99
+ )
54
100
  ) : (
55
101
  <EmptyRow message={t("linkedEmpty")} />
56
102
  )}
@@ -64,15 +110,46 @@ export const LinkedAccounts = () => {
64
110
  >
65
111
  {t("unlinkedLoginProviders")}
66
112
  </Title>
113
+ <LinkedAccountsToolbar
114
+ onFilter={(search) =>
115
+ setParamsUnlinked({ ...paramsUnlinked, first: 0, search })
116
+ }
117
+ count={unlinkedAccounts.length}
118
+ first={paramsUnlinked["first"]}
119
+ max={paramsUnlinked["max"]}
120
+ onNextClick={() => {
121
+ setParamsUnlinked({
122
+ ...paramsUnlinked,
123
+ first: paramsUnlinked.first + paramsUnlinked.max - 1,
124
+ });
125
+ }}
126
+ onPreviousClick={() =>
127
+ setParamsUnlinked({
128
+ ...paramsUnlinked,
129
+ first: paramsUnlinked.first - paramsUnlinked.max + 1,
130
+ })
131
+ }
132
+ onPerPageSelect={(first, max) =>
133
+ setParamsUnlinked({
134
+ ...paramsUnlinked,
135
+ first,
136
+ max,
137
+ })
138
+ }
139
+ hasNext={unlinkedAccounts.length > paramsUnlinked.max - 1}
140
+ />
67
141
  <DataList id="unlinked-idps" aria-label={t("unlinkedLoginProviders")}>
68
- {unLinkedAccounts.length > 0 ? (
69
- unLinkedAccounts.map((account) => (
70
- <AccountRow
71
- key={account.providerName}
72
- account={account}
73
- refresh={refresh}
74
- />
75
- ))
142
+ {unlinkedAccounts.length > 0 ? (
143
+ unlinkedAccounts.map(
144
+ (account, index) =>
145
+ index !== paramsUnlinked.max - 1 && (
146
+ <AccountRow
147
+ key={account.providerName}
148
+ account={account}
149
+ refresh={refresh}
150
+ />
151
+ ),
152
+ )
76
153
  ) : (
77
154
  <EmptyRow message={t("unlinkedEmpty")} />
78
155
  )}
@@ -0,0 +1,88 @@
1
+ import { useState } from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import {
4
+ Pagination,
5
+ SearchInput,
6
+ PaginationToggleTemplateProps,
7
+ Toolbar,
8
+ ToolbarContent,
9
+ ToolbarItem,
10
+ } from "@patternfly/react-core";
11
+
12
+ type LinkedAccountsToolbarProps = {
13
+ onFilter: (nameFilter: string) => void;
14
+ count: number;
15
+ first: number;
16
+ max: number;
17
+ onNextClick: (page: number) => void;
18
+ onPreviousClick: (page: number) => void;
19
+ onPerPageSelect: (max: number, first: number) => void;
20
+ hasNext: boolean;
21
+ };
22
+
23
+ export const LinkedAccountsToolbar = ({
24
+ count,
25
+ first,
26
+ max,
27
+ onNextClick,
28
+ onPreviousClick,
29
+ onPerPageSelect,
30
+ onFilter,
31
+ hasNext,
32
+ }: LinkedAccountsToolbarProps) => {
33
+ const { t } = useTranslation();
34
+ const [nameFilter, setNameFilter] = useState("");
35
+
36
+ const page = Math.round(first / max) + 1;
37
+ return (
38
+ <Toolbar>
39
+ <ToolbarContent>
40
+ <ToolbarItem>
41
+ <SearchInput
42
+ placeholder={t("filterByName")}
43
+ aria-label={t("filterByName")}
44
+ value={nameFilter}
45
+ onChange={(_, value) => {
46
+ setNameFilter(value);
47
+ }}
48
+ onSearch={() => onFilter(nameFilter)}
49
+ onKeyDown={(e) => {
50
+ if (e.key === "Enter") {
51
+ onFilter(nameFilter);
52
+ }
53
+ }}
54
+ onClear={() => {
55
+ setNameFilter("");
56
+ onFilter("");
57
+ }}
58
+ />
59
+ </ToolbarItem>
60
+ <ToolbarItem variant="pagination">
61
+ <Pagination
62
+ isCompact
63
+ perPageOptions={[
64
+ { title: "5", value: 6 },
65
+ { title: "10", value: 11 },
66
+ { title: "20", value: 21 },
67
+ ]}
68
+ toggleTemplate={({
69
+ firstIndex,
70
+ lastIndex,
71
+ }: PaginationToggleTemplateProps) => (
72
+ <b>
73
+ {firstIndex && firstIndex > 1 ? firstIndex - 1 : firstIndex} -{" "}
74
+ {lastIndex && lastIndex > 1 ? lastIndex - 1 : lastIndex}
75
+ </b>
76
+ )}
77
+ itemCount={count + (page - 1) * max + (hasNext ? 1 : 0)}
78
+ page={page}
79
+ perPage={max}
80
+ onNextClick={(_, p) => onNextClick((p - 1) * max)}
81
+ onPreviousClick={(_, p) => onPreviousClick((p - 1) * max)}
82
+ onPerPageSelect={(_, m, f) => onPerPageSelect(f - 1, m)}
83
+ />
84
+ </ToolbarItem>
85
+ </ToolbarContent>
86
+ </Toolbar>
87
+ );
88
+ };
@@ -101,7 +101,7 @@ export const SigningIn = () => {
101
101
  className="pf-v5-u-max-width"
102
102
  style={maxWidth}
103
103
  >
104
- {credential.userLabel || t(credential.type as TFuncKey)}
104
+ {t(credential.userLabel) || t(credential.type as TFuncKey)}
105
105
  </DataListCell>,
106
106
  ];
107
107
 
@@ -3,6 +3,7 @@ import {
3
3
  type KeycloakContext,
4
4
  } from "@keycloakify/keycloak-account-ui/ui-shared";
5
5
 
6
+ import OrganizationRepresentation from "@keycloak/keycloak-admin-client/lib/defs/organizationRepresentation";
6
7
  import { joinPath } from "@keycloakify/keycloak-account-ui/utils/joinPath";
7
8
  import { parseResponse } from "@keycloakify/keycloak-account-ui/api/parse-response";
8
9
  import {
@@ -108,8 +109,22 @@ export async function getCredentials({ signal, context }: CallOptions) {
108
109
  return parseResponse<CredentialContainer[]>(response);
109
110
  }
110
111
 
111
- export async function getLinkedAccounts({ signal, context }: CallOptions) {
112
- const response = await request("/linked-accounts", context, { signal });
112
+ export type LinkedAccountQueryParams = PaginationParams & {
113
+ search?: string;
114
+ linked?: boolean;
115
+ };
116
+
117
+ export async function getLinkedAccounts(
118
+ { signal, context }: CallOptions,
119
+ query: LinkedAccountQueryParams,
120
+ ) {
121
+ const response = await request("/linked-accounts", context, {
122
+ searchParams: Object.entries(query).reduce(
123
+ (acc, [key, value]) => ({ ...acc, [key]: value.toString() }),
124
+ {},
125
+ ),
126
+ signal,
127
+ });
113
128
  return parseResponse<LinkedAccountRepresentation[]>(response);
114
129
  }
115
130
 
@@ -156,3 +171,8 @@ export async function getGroups({ signal, context }: CallOptions) {
156
171
  });
157
172
  return parseResponse<Group[]>(response);
158
173
  }
174
+
175
+ export async function getUserOrganizations({ signal, context }: CallOptions) {
176
+ const response = await request("/organizations", context, { signal });
177
+ return parseResponse<OrganizationRepresentation[]>(response);
178
+ }
@@ -7,15 +7,15 @@ export function parseLinks(response: Response): Links {
7
7
  const linkHeader = response.headers.get("link");
8
8
 
9
9
  if (!linkHeader) {
10
- throw new Error("Attempted to parse links, but no header was found.");
10
+ return {};
11
11
  }
12
12
 
13
13
  const links = linkHeader.split(/,\s*</);
14
14
  return links.reduce<Links>((acc: Links, link: string) => {
15
- const matcher = link.match(/<?([^>]*)>(.*)/);
15
+ const matcher = /<?([^>]*)>(.*)/.exec(link);
16
16
  if (!matcher) return {};
17
17
  const linkUrl = matcher[1];
18
- const rel = matcher[2].match(/\s*(.+)\s*=\s*"?([^"]+)"?/);
18
+ const rel = /\s*(.+)\s*=\s*"?([^"]+)"?/.exec(matcher[2]);
19
19
  if (rel) {
20
20
  const link: Record<string, string> = {};
21
21
  for (const [key, value] of new URL(linkUrl).searchParams.entries()) {
@@ -1,7 +1,17 @@
1
- import { isRecord } from "@keycloakify/keycloak-account-ui/utils/isRecord";
1
+ import {
2
+ getNetworkErrorMessage,
3
+ getNetworkErrorDescription,
4
+ } from "@keycloakify/keycloak-account-ui/ui-shared";
2
5
  import { CONTENT_TYPE_HEADER, CONTENT_TYPE_JSON } from "@keycloakify/keycloak-account-ui/api/constants";
3
6
 
4
- export class ApiError extends Error {}
7
+ export class ApiError extends Error {
8
+ description?: string;
9
+
10
+ constructor(message: string, description?: string) {
11
+ super(message);
12
+ this.description = description;
13
+ }
14
+ }
5
15
 
6
16
  export async function parseResponse<T>(response: Response): Promise<T> {
7
17
  const contentType = response.headers.get(CONTENT_TYPE_HEADER);
@@ -16,7 +26,16 @@ export async function parseResponse<T>(response: Response): Promise<T> {
16
26
  const data = await parseJSON(response);
17
27
 
18
28
  if (!response.ok) {
19
- throw new ApiError(getErrorMessage(data));
29
+ const message = getNetworkErrorMessage(data);
30
+ const description = getNetworkErrorDescription(data);
31
+
32
+ if (!message) {
33
+ throw new Error(
34
+ "Unable to retrieve error message from response, no matching key found.",
35
+ );
36
+ }
37
+
38
+ throw new ApiError(message, description);
20
39
  }
21
40
 
22
41
  return data as T;
@@ -31,23 +50,3 @@ async function parseJSON(response: Response): Promise<unknown> {
31
50
  });
32
51
  }
33
52
  }
34
-
35
- function getErrorMessage(data: unknown): string {
36
- if (!isRecord(data)) {
37
- throw new Error("Unable to retrieve error message from response.");
38
- }
39
-
40
- const errorKeys = ["error_description", "errorMessage", "error"];
41
-
42
- for (const key of errorKeys) {
43
- const value = data[key];
44
-
45
- if (typeof value === "string") {
46
- return value;
47
- }
48
- }
49
-
50
- throw new Error(
51
- "Unable to retrieve error message from response, no matching key found.",
52
- );
53
- }
@@ -66,7 +66,7 @@ export const token = (keycloak: Keycloak) =>
66
66
  async function getAccessToken() {
67
67
  try {
68
68
  await keycloak.updateToken(5);
69
- } catch (error) {
69
+ } catch {
70
70
  await keycloak.login();
71
71
  }
72
72
 
package/src/api.ts CHANGED
@@ -27,13 +27,7 @@ export const fetchResources = async (
27
27
  { searchParams: shared ? requestParams : undefined, signal },
28
28
  );
29
29
 
30
- let links: Links;
31
-
32
- try {
33
- links = parseLinks(response);
34
- } catch (error) {
35
- links = {};
36
- }
30
+ const links = parseLinks(response);
37
31
 
38
32
  return {
39
33
  data: checkResponse(await response.json()),