@thunderid/react 1.8.0 → 1.9.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.
Files changed (200) hide show
  1. package/dist/cjs/components/account/UserProfile/BaseUserProfile.cjs +1 -1
  2. package/dist/cjs/components/admin/AgentDetails/AgentDetails.cjs +13 -2
  3. package/dist/cjs/components/admin/AgentDetails/AgentDetails.cjs.map +1 -1
  4. package/dist/cjs/components/admin/AgentDetails/BaseAgentDetails.cjs +25 -7
  5. package/dist/cjs/components/admin/AgentDetails/BaseAgentDetails.cjs.map +1 -1
  6. package/dist/cjs/components/admin/ApplicationDetails/ApplicationDetails.cjs +15 -2
  7. package/dist/cjs/components/admin/ApplicationDetails/ApplicationDetails.cjs.map +1 -1
  8. package/dist/cjs/components/admin/ApplicationDetails/BaseApplicationDetails.cjs +24 -7
  9. package/dist/cjs/components/admin/ApplicationDetails/BaseApplicationDetails.cjs.map +1 -1
  10. package/dist/cjs/components/admin/GroupMembers/GroupMembers.cjs +2 -1
  11. package/dist/cjs/components/admin/GroupMembers/GroupMembers.cjs.map +1 -1
  12. package/dist/cjs/components/admin/RoleAssignments/RoleAssignments.cjs +2 -1
  13. package/dist/cjs/components/admin/RoleAssignments/RoleAssignments.cjs.map +1 -1
  14. package/dist/cjs/components/admin/UserDetails/BaseUserDetails.cjs +32 -14
  15. package/dist/cjs/components/admin/UserDetails/BaseUserDetails.cjs.map +1 -1
  16. package/dist/cjs/components/admin/UserDetails/UserDetails.cjs +14 -2
  17. package/dist/cjs/components/admin/UserDetails/UserDetails.cjs.map +1 -1
  18. package/dist/cjs/components/admin/shared/AccountLifecycleParts.cjs +105 -0
  19. package/dist/cjs/components/admin/shared/AccountLifecycleParts.cjs.map +1 -0
  20. package/dist/cjs/components/admin/shared/ApplicationFormFields.cjs +1 -1
  21. package/dist/cjs/components/auth/AcceptInvite/BaseAcceptInvite.cjs +4 -5
  22. package/dist/cjs/components/auth/AcceptInvite/BaseAcceptInvite.cjs.map +1 -1
  23. package/dist/cjs/components/auth/SignIn/SignIn.cjs +5 -5
  24. package/dist/cjs/components/auth/SignIn/SignIn.cjs.map +1 -1
  25. package/dist/cjs/components/auth/flow/AuthOptionFactory.cjs +4 -5
  26. package/dist/cjs/components/auth/flow/AuthOptionFactory.cjs.map +1 -1
  27. package/dist/cjs/components/auth/flow/Consent.cjs +53 -28
  28. package/dist/cjs/components/auth/flow/Consent.cjs.map +1 -1
  29. package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.cjs +104 -0
  30. package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.cjs.map +1 -0
  31. package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.styles.cjs +59 -0
  32. package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.styles.cjs.map +1 -0
  33. package/dist/cjs/components/auth/flow/ConsentDetailField.cjs +171 -0
  34. package/dist/cjs/components/auth/flow/ConsentDetailField.cjs.map +1 -0
  35. package/dist/cjs/components/auth/flow/ConsentDetailField.styles.cjs +85 -0
  36. package/dist/cjs/components/auth/flow/ConsentDetailField.styles.cjs.map +1 -0
  37. package/dist/cjs/components/auth/flow/ConsentDetailText.cjs +63 -0
  38. package/dist/cjs/components/auth/flow/ConsentDetailText.cjs.map +1 -0
  39. package/dist/cjs/components/auth/flow/ConsentDetailText.styles.cjs +83 -0
  40. package/dist/cjs/components/auth/flow/ConsentDetailText.styles.cjs.map +1 -0
  41. package/dist/cjs/components/auth/flow/FieldFactory.cjs +1 -1
  42. package/dist/cjs/components/auth/flow/resolveConsentText.cjs +25 -0
  43. package/dist/cjs/components/auth/flow/resolveConsentText.cjs.map +1 -0
  44. package/dist/cjs/components/primitives/KeyValueInput/KeyValueInput.cjs +1 -1
  45. package/dist/cjs/components/primitives/MultiInput/MultiInput.cjs +1 -1
  46. package/dist/cjs/components/primitives/PasswordField/PasswordField.cjs +1 -1
  47. package/dist/cjs/contexts/Theme/ThemeProvider.cjs +36 -6
  48. package/dist/cjs/contexts/Theme/ThemeProvider.cjs.map +1 -1
  49. package/dist/cjs/contexts/Theme/ThemeRootContext.cjs +12 -0
  50. package/dist/cjs/contexts/Theme/ThemeRootContext.cjs.map +1 -0
  51. package/dist/cjs/hooks/auth/useConsentDetailField.cjs +357 -0
  52. package/dist/cjs/hooks/auth/useConsentDetailField.cjs.map +1 -0
  53. package/dist/cjs/hooks/management/useAccountLifecycle.cjs +59 -0
  54. package/dist/cjs/hooks/management/useAccountLifecycle.cjs.map +1 -0
  55. package/dist/cjs/index.cjs +66 -1
  56. package/dist/cjs/utils/formatConsentDetailValue.cjs +26 -0
  57. package/dist/cjs/utils/formatConsentDetailValue.cjs.map +1 -0
  58. package/dist/cjs/utils/getConsentDetailLayout.cjs +44 -0
  59. package/dist/cjs/utils/getConsentDetailLayout.cjs.map +1 -0
  60. package/dist/cjs/utils/getConsentDetailListDisplay.cjs +30 -0
  61. package/dist/cjs/utils/getConsentDetailListDisplay.cjs.map +1 -0
  62. package/dist/cjs/utils/isConsentApprovalBlocked.cjs +41 -0
  63. package/dist/cjs/utils/isConsentApprovalBlocked.cjs.map +1 -0
  64. package/dist/cjs/utils/isConsentDetailPlainList.cjs +24 -0
  65. package/dist/cjs/utils/isConsentDetailPlainList.cjs.map +1 -0
  66. package/dist/cjs/utils/isConsentDetailStructured.cjs +15 -0
  67. package/dist/cjs/utils/isConsentDetailStructured.cjs.map +1 -0
  68. package/dist/cjs/utils/isConsentDetailTextClamped.cjs +25 -0
  69. package/dist/cjs/utils/isConsentDetailTextClamped.cjs.map +1 -0
  70. package/dist/components/account/UserProfile/BaseUserProfile.js +1 -1
  71. package/dist/components/admin/AgentDetails/AgentDetails.d.ts +8 -1
  72. package/dist/components/admin/AgentDetails/AgentDetails.d.ts.map +1 -1
  73. package/dist/components/admin/AgentDetails/AgentDetails.js +13 -2
  74. package/dist/components/admin/AgentDetails/AgentDetails.js.map +1 -1
  75. package/dist/components/admin/AgentDetails/BaseAgentDetails.d.ts +21 -1
  76. package/dist/components/admin/AgentDetails/BaseAgentDetails.d.ts.map +1 -1
  77. package/dist/components/admin/AgentDetails/BaseAgentDetails.js +25 -7
  78. package/dist/components/admin/AgentDetails/BaseAgentDetails.js.map +1 -1
  79. package/dist/components/admin/ApplicationDetails/ApplicationDetails.d.ts +15 -1
  80. package/dist/components/admin/ApplicationDetails/ApplicationDetails.d.ts.map +1 -1
  81. package/dist/components/admin/ApplicationDetails/ApplicationDetails.js +15 -2
  82. package/dist/components/admin/ApplicationDetails/ApplicationDetails.js.map +1 -1
  83. package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.d.ts +20 -1
  84. package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.d.ts.map +1 -1
  85. package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.js +24 -7
  86. package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.js.map +1 -1
  87. package/dist/components/admin/GroupMembers/GroupMembers.d.ts +7 -0
  88. package/dist/components/admin/GroupMembers/GroupMembers.d.ts.map +1 -1
  89. package/dist/components/admin/GroupMembers/GroupMembers.js +2 -1
  90. package/dist/components/admin/GroupMembers/GroupMembers.js.map +1 -1
  91. package/dist/components/admin/RoleAssignments/RoleAssignments.d.ts +7 -0
  92. package/dist/components/admin/RoleAssignments/RoleAssignments.d.ts.map +1 -1
  93. package/dist/components/admin/RoleAssignments/RoleAssignments.js +2 -1
  94. package/dist/components/admin/RoleAssignments/RoleAssignments.js.map +1 -1
  95. package/dist/components/admin/UserDetails/BaseUserDetails.d.ts +22 -1
  96. package/dist/components/admin/UserDetails/BaseUserDetails.d.ts.map +1 -1
  97. package/dist/components/admin/UserDetails/BaseUserDetails.js +32 -14
  98. package/dist/components/admin/UserDetails/BaseUserDetails.js.map +1 -1
  99. package/dist/components/admin/UserDetails/UserDetails.d.ts +15 -1
  100. package/dist/components/admin/UserDetails/UserDetails.d.ts.map +1 -1
  101. package/dist/components/admin/UserDetails/UserDetails.js +14 -2
  102. package/dist/components/admin/UserDetails/UserDetails.js.map +1 -1
  103. package/dist/components/admin/shared/AccountLifecycleParts.d.ts +32 -0
  104. package/dist/components/admin/shared/AccountLifecycleParts.d.ts.map +1 -0
  105. package/dist/components/admin/shared/AccountLifecycleParts.js +101 -0
  106. package/dist/components/admin/shared/AccountLifecycleParts.js.map +1 -0
  107. package/dist/components/admin/shared/ApplicationFormFields.js +1 -1
  108. package/dist/components/auth/AcceptInvite/BaseAcceptInvite.d.ts.map +1 -1
  109. package/dist/components/auth/AcceptInvite/BaseAcceptInvite.js +5 -6
  110. package/dist/components/auth/AcceptInvite/BaseAcceptInvite.js.map +1 -1
  111. package/dist/components/auth/SignIn/SignIn.d.ts.map +1 -1
  112. package/dist/components/auth/SignIn/SignIn.js +6 -6
  113. package/dist/components/auth/SignIn/SignIn.js.map +1 -1
  114. package/dist/components/auth/flow/AuthOptionFactory.d.ts.map +1 -1
  115. package/dist/components/auth/flow/AuthOptionFactory.js +5 -6
  116. package/dist/components/auth/flow/AuthOptionFactory.js.map +1 -1
  117. package/dist/components/auth/flow/Consent.d.ts +6 -0
  118. package/dist/components/auth/flow/Consent.d.ts.map +1 -1
  119. package/dist/components/auth/flow/Consent.js +54 -29
  120. package/dist/components/auth/flow/Consent.js.map +1 -1
  121. package/dist/components/auth/flow/ConsentAuthorizationDetail.d.ts +68 -0
  122. package/dist/components/auth/flow/ConsentAuthorizationDetail.d.ts.map +1 -0
  123. package/dist/components/auth/flow/ConsentAuthorizationDetail.js +100 -0
  124. package/dist/components/auth/flow/ConsentAuthorizationDetail.js.map +1 -0
  125. package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.d.ts +10 -0
  126. package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.d.ts.map +1 -0
  127. package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.js +57 -0
  128. package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.js.map +1 -0
  129. package/dist/components/auth/flow/ConsentDetailField.d.ts +39 -0
  130. package/dist/components/auth/flow/ConsentDetailField.d.ts.map +1 -0
  131. package/dist/components/auth/flow/ConsentDetailField.js +168 -0
  132. package/dist/components/auth/flow/ConsentDetailField.js.map +1 -0
  133. package/dist/components/auth/flow/ConsentDetailField.styles.d.ts +11 -0
  134. package/dist/components/auth/flow/ConsentDetailField.styles.d.ts.map +1 -0
  135. package/dist/components/auth/flow/ConsentDetailField.styles.js +83 -0
  136. package/dist/components/auth/flow/ConsentDetailField.styles.js.map +1 -0
  137. package/dist/components/auth/flow/ConsentDetailText.d.ts +53 -0
  138. package/dist/components/auth/flow/ConsentDetailText.d.ts.map +1 -0
  139. package/dist/components/auth/flow/ConsentDetailText.js +58 -0
  140. package/dist/components/auth/flow/ConsentDetailText.js.map +1 -0
  141. package/dist/components/auth/flow/ConsentDetailText.styles.d.ts +20 -0
  142. package/dist/components/auth/flow/ConsentDetailText.styles.d.ts.map +1 -0
  143. package/dist/components/auth/flow/ConsentDetailText.styles.js +80 -0
  144. package/dist/components/auth/flow/ConsentDetailText.styles.js.map +1 -0
  145. package/dist/components/auth/flow/FieldFactory.js +1 -1
  146. package/dist/components/auth/flow/resolveConsentText.d.ts +13 -0
  147. package/dist/components/auth/flow/resolveConsentText.d.ts.map +1 -0
  148. package/dist/components/auth/flow/resolveConsentText.js +23 -0
  149. package/dist/components/auth/flow/resolveConsentText.js.map +1 -0
  150. package/dist/components/primitives/KeyValueInput/KeyValueInput.js +1 -1
  151. package/dist/components/primitives/MultiInput/MultiInput.js +1 -1
  152. package/dist/components/primitives/PasswordField/PasswordField.js +1 -1
  153. package/dist/contexts/Theme/ThemeProvider.d.ts +2 -1
  154. package/dist/contexts/Theme/ThemeProvider.d.ts.map +1 -1
  155. package/dist/contexts/Theme/ThemeProvider.js +37 -7
  156. package/dist/contexts/Theme/ThemeProvider.js.map +1 -1
  157. package/dist/contexts/Theme/ThemeRootContext.d.ts +11 -0
  158. package/dist/contexts/Theme/ThemeRootContext.d.ts.map +1 -0
  159. package/dist/contexts/Theme/ThemeRootContext.js +10 -0
  160. package/dist/contexts/Theme/ThemeRootContext.js.map +1 -0
  161. package/dist/hooks/auth/useConsentDetailField.d.ts +130 -0
  162. package/dist/hooks/auth/useConsentDetailField.d.ts.map +1 -0
  163. package/dist/hooks/auth/useConsentDetailField.js +354 -0
  164. package/dist/hooks/auth/useConsentDetailField.js.map +1 -0
  165. package/dist/hooks/management/useAccountLifecycle.d.ts +49 -0
  166. package/dist/hooks/management/useAccountLifecycle.d.ts.map +1 -0
  167. package/dist/hooks/management/useAccountLifecycle.js +56 -0
  168. package/dist/hooks/management/useAccountLifecycle.js.map +1 -0
  169. package/dist/index.d.ts +16 -4
  170. package/dist/index.d.ts.map +1 -1
  171. package/dist/index.js +11 -3
  172. package/dist/utils/formatConsentDetailValue.d.ts +16 -0
  173. package/dist/utils/formatConsentDetailValue.d.ts.map +1 -0
  174. package/dist/utils/formatConsentDetailValue.js +25 -0
  175. package/dist/utils/formatConsentDetailValue.js.map +1 -0
  176. package/dist/utils/getConsentDetailLayout.d.ts +32 -0
  177. package/dist/utils/getConsentDetailLayout.d.ts.map +1 -0
  178. package/dist/utils/getConsentDetailLayout.js +43 -0
  179. package/dist/utils/getConsentDetailLayout.js.map +1 -0
  180. package/dist/utils/getConsentDetailListDisplay.d.ts +30 -0
  181. package/dist/utils/getConsentDetailListDisplay.d.ts.map +1 -0
  182. package/dist/utils/getConsentDetailListDisplay.js +30 -0
  183. package/dist/utils/getConsentDetailListDisplay.js.map +1 -0
  184. package/dist/utils/isConsentApprovalBlocked.d.ts +17 -0
  185. package/dist/utils/isConsentApprovalBlocked.d.ts.map +1 -0
  186. package/dist/utils/isConsentApprovalBlocked.js +39 -0
  187. package/dist/utils/isConsentApprovalBlocked.js.map +1 -0
  188. package/dist/utils/isConsentDetailPlainList.d.ts +15 -0
  189. package/dist/utils/isConsentDetailPlainList.d.ts.map +1 -0
  190. package/dist/utils/isConsentDetailPlainList.js +23 -0
  191. package/dist/utils/isConsentDetailPlainList.js.map +1 -0
  192. package/dist/utils/isConsentDetailStructured.d.ts +10 -0
  193. package/dist/utils/isConsentDetailStructured.d.ts.map +1 -0
  194. package/dist/utils/isConsentDetailStructured.js +14 -0
  195. package/dist/utils/isConsentDetailStructured.js.map +1 -0
  196. package/dist/utils/isConsentDetailTextClamped.d.ts +20 -0
  197. package/dist/utils/isConsentDetailTextClamped.d.ts.map +1 -0
  198. package/dist/utils/isConsentDetailTextClamped.js +24 -0
  199. package/dist/utils/isConsentDetailTextClamped.js.map +1 -0
  200. package/package.json +2 -2
@@ -6,6 +6,7 @@ import TextField_default from "../../primitives/TextField/TextField.js";
6
6
  import { Avatar } from "../../primitives/Avatar/Avatar.js";
7
7
  import useAdminPartStyles_default from "../shared/useAdminPartStyles.js";
8
8
  import AdminSection_default from "../shared/AdminSection.js";
9
+ import { AccessStatusBadge, AccountLifecycleButtons } from "../shared/AccountLifecycleParts.js";
9
10
  import { ChipList, ConfirmButton, DetailList, Panel } from "../shared/AdminParts.js";
10
11
  import { resolveManagedIdentityName } from "@thunderid/browser";
11
12
  import { useState } from "react";
@@ -20,7 +21,7 @@ const stringify = (value) => {
20
21
  * Shows a user's attributes, type, organization unit and groups. Holds no data of its own: pass the
21
22
  * user and handle deletion.
22
23
  */
23
- const BaseUserDetails = ({ actions, children, className, error = null, groups = [], hiddenAttributes = ["password"], isDeleting = false, isLoading = false, isUpdating = false, onDelete, onUpdate, preferences, user }) => {
24
+ const BaseUserDetails = ({ actions, children, className, error = null, groups = [], hiddenAttributes = ["password"], isDeleting = false, isLoading = false, isRunningLifecycleAction = false, isUpdating = false, lifecycleActions = [], onDelete, onLifecycleAction, onUpdate, preferences, user }) => {
24
25
  const { t } = useTranslation_default(preferences?.i18n);
25
26
  const styles = useAdminPartStyles_default();
26
27
  const [draft, setDraft] = useState(null);
@@ -35,8 +36,11 @@ const BaseUserDetails = ({ actions, children, className, error = null, groups =
35
36
  groups,
36
37
  isDeleting,
37
38
  isLoading,
39
+ isRunningLifecycleAction,
38
40
  isUpdating,
41
+ lifecycleActions: onLifecycleAction && user ? lifecycleActions : [],
39
42
  onDelete: isWritable ? onDelete : void 0,
43
+ onLifecycleAction: user ? onLifecycleAction : void 0,
40
44
  onUpdate: isWritable ? onUpdate : void 0,
41
45
  user
42
46
  })
@@ -75,12 +79,22 @@ const BaseUserDetails = ({ actions, children, className, error = null, groups =
75
79
  title: displayName,
76
80
  description: t("admin.users.details.subtitle", { type: user.type }),
77
81
  preferences,
78
- actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [actions, onDelete && !user.isReadOnly && /* @__PURE__ */ jsx(ConfirmButton, {
79
- confirmText: t("admin.users.details.delete.confirm", { name: displayName }),
80
- isLoading: isDeleting,
81
- onConfirm: onDelete,
82
- children: t("admin.users.details.delete.action")
83
- })] }),
82
+ actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [
83
+ actions,
84
+ onLifecycleAction && /* @__PURE__ */ jsx(AccountLifecycleButtons, {
85
+ actions: lifecycleActions,
86
+ collectsOperatorNote: true,
87
+ isRunning: isRunningLifecycleAction,
88
+ name: displayName,
89
+ onAction: onLifecycleAction
90
+ }),
91
+ onDelete && !user.isReadOnly && /* @__PURE__ */ jsx(ConfirmButton, {
92
+ confirmText: t("admin.users.details.delete.confirm", { name: displayName }),
93
+ isLoading: isDeleting,
94
+ onConfirm: onDelete,
95
+ children: t("admin.users.details.delete.action")
96
+ })
97
+ ] }),
84
98
  children: [
85
99
  error && /* @__PURE__ */ jsx(Alert_default, {
86
100
  variant: "error",
@@ -89,13 +103,17 @@ const BaseUserDetails = ({ actions, children, className, error = null, groups =
89
103
  }),
90
104
  /* @__PURE__ */ jsxs("div", {
91
105
  className: styles["row"],
92
- children: [/* @__PURE__ */ jsx(Avatar, {
93
- name: displayName,
94
- size: 48
95
- }), /* @__PURE__ */ jsx("span", {
96
- className: styles["muted"],
97
- children: user.ouHandle ?? user.ouId
98
- })]
106
+ children: [
107
+ /* @__PURE__ */ jsx(Avatar, {
108
+ name: displayName,
109
+ size: 48
110
+ }),
111
+ /* @__PURE__ */ jsx("span", {
112
+ className: styles["muted"],
113
+ children: user.ouHandle ?? user.ouId
114
+ }),
115
+ /* @__PURE__ */ jsx(AccessStatusBadge, { status: user.status?.value })
116
+ ]
99
117
  }),
100
118
  /* @__PURE__ */ jsx(Panel, {
101
119
  title: t("admin.users.details.attributes"),
@@ -1 +1 @@
1
- {"version":3,"file":"BaseUserDetails.js","names":["BaseUserDetails: FC<BaseUserDetailsProps>","useTranslation","styles: Record<string, string>","useAdminPartStyles","isWritable: boolean","AdminSection","Spinner","Alert","displayName: string","attributes: [string, unknown][]","editableAttributes: [string, string][]","Button","TextField"],"sources":["../../../../src/components/admin/UserDetails/BaseUserDetails.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {resolveManagedIdentityName, ManagedUser, MembershipGroup, Preferences} from '@thunderid/browser';\nimport {ChangeEvent, FC, ReactElement, ReactNode, useState} from 'react';\nimport useTranslation from '../../../hooks/useTranslation';\nimport Alert from '../../primitives/Alert/Alert';\nimport {Avatar} from '../../primitives/Avatar/Avatar';\nimport Button from '../../primitives/Button/Button';\nimport Spinner from '../../primitives/Spinner/Spinner';\nimport TextField from '../../primitives/TextField/TextField';\nimport {ChipList, ConfirmButton, DetailList, Panel} from '../shared/AdminParts';\nimport AdminSection from '../shared/AdminSection';\nimport useAdminPartStyles from '../shared/useAdminPartStyles';\n\n/**\n * What {@link BaseUserDetails} hands its `children` render function, so the user can be shown with any UI.\n */\nexport interface BaseUserDetailsRenderProps {\n /**\n * The user's attributes, without the hidden ones.\n */\n attributes: Record<string, unknown>;\n /**\n * The user's display name, or an empty string while there is no user.\n */\n displayName: string;\n error: string | null;\n groups: MembershipGroup[];\n isDeleting: boolean;\n isLoading: boolean;\n isUpdating: boolean;\n /**\n * Deletes the user. Undefined when deletion is not allowed, including for read-only users.\n */\n onDelete?: () => void;\n /**\n * Saves the given attributes. Undefined when editing is not allowed, including for read-only users.\n */\n onUpdate?: (attributes: Record<string, unknown>) => void;\n user?: ManagedUser;\n}\n\nexport interface BaseUserDetailsProps {\n /**\n * Controls rendered next to the user's name.\n */\n actions?: ReactNode;\n /**\n * Renders custom UI in place of the default view. Receives the user, their visible attributes and\n * groups, the loading and error state, and the delete and update handlers.\n */\n children?: (props: BaseUserDetailsRenderProps) => ReactNode;\n className?: string;\n error?: string | null;\n /**\n * The groups the user belongs to.\n */\n groups?: MembershipGroup[];\n /**\n * Attribute names that are never shown, such as credentials.\n * @default ['password']\n */\n hiddenAttributes?: string[];\n isDeleting?: boolean;\n isLoading?: boolean;\n isUpdating?: boolean;\n /**\n * Deletes the user. The delete action is hidden when omitted.\n */\n onDelete?: () => void;\n /**\n * Saves edited attributes. Text attributes become editable only when set. Receives every\n * attribute, edited or not.\n */\n onUpdate?: (attributes: Record<string, unknown>) => void;\n preferences?: Preferences;\n user?: ManagedUser;\n}\n\nconst stringify = (value: unknown): string => {\n if (value === null || value === undefined) {\n return '';\n }\n\n return typeof value === 'object' ? JSON.stringify(value) : String(value as string | number | boolean);\n};\n\n/**\n * Shows a user's attributes, type, organization unit and groups. Holds no data of its own: pass the\n * user and handle deletion.\n */\nconst BaseUserDetails: FC<BaseUserDetailsProps> = ({\n actions,\n children,\n className,\n error = null,\n groups = [],\n hiddenAttributes = ['password'],\n isDeleting = false,\n isLoading = false,\n isUpdating = false,\n onDelete,\n onUpdate,\n preferences,\n user,\n}: BaseUserDetailsProps): ReactElement => {\n const {t} = useTranslation(preferences?.i18n);\n const styles: Record<string, string> = useAdminPartStyles();\n const [draft, setDraft] = useState<Record<string, string> | null>(null);\n\n if (children) {\n const isWritable: boolean = Boolean(user) && !user?.isReadOnly;\n\n return (\n <div className={className}>\n {children({\n attributes: Object.fromEntries(\n Object.entries(user?.attributes ?? {}).filter(\n ([name]: [string, unknown]) => !hiddenAttributes.includes(name),\n ),\n ),\n displayName: user ? resolveManagedIdentityName(user) : '',\n error,\n groups,\n isDeleting,\n isLoading,\n isUpdating,\n onDelete: isWritable ? onDelete : undefined,\n onUpdate: isWritable ? onUpdate : undefined,\n user,\n })}\n </div>\n );\n }\n\n if (isLoading && !user) {\n return (\n <AdminSection block=\"user-details\" className={className} preferences={preferences}>\n <span className={styles['muted']} role=\"status\">\n <Spinner size=\"small\" /> {t('admin.common.loading')}\n </span>\n </AdminSection>\n );\n }\n\n if (!user) {\n return (\n <AdminSection block=\"user-details\" className={className} preferences={preferences}>\n <Alert variant=\"error\" role=\"alert\">\n {error ?? t('admin.common.errors.not_found')}\n </Alert>\n </AdminSection>\n );\n }\n\n const displayName: string = resolveManagedIdentityName(user);\n const attributes: [string, unknown][] = Object.entries(user.attributes ?? {}).filter(\n ([name]: [string, unknown]) => !hiddenAttributes.includes(name),\n );\n const editableAttributes: [string, string][] = attributes.filter(\n (entry: [string, unknown]): entry is [string, string] => typeof entry[1] === 'string',\n );\n\n return (\n <AdminSection\n block=\"user-details\"\n className={className}\n title={displayName}\n description={t('admin.users.details.subtitle', {type: user.type})}\n preferences={preferences}\n actions={\n <>\n {actions}\n {onDelete && !user.isReadOnly && (\n <ConfirmButton\n confirmText={t('admin.users.details.delete.confirm', {name: displayName})}\n isLoading={isDeleting}\n onConfirm={onDelete}\n >\n {t('admin.users.details.delete.action')}\n </ConfirmButton>\n )}\n </>\n }\n >\n {error && (\n <Alert variant=\"error\" role=\"alert\">\n {error}\n </Alert>\n )}\n <div className={styles['row']}>\n <Avatar name={displayName} size={48} />\n <span className={styles['muted']}>{user.ouHandle ?? user.ouId}</span>\n </div>\n <Panel\n title={t('admin.users.details.attributes')}\n actions={\n onUpdate && !user.isReadOnly && !draft && editableAttributes.length > 0 ? (\n <Button\n variant=\"outline\"\n size=\"small\"\n onClick={(): void => setDraft(Object.fromEntries(editableAttributes))}\n >\n {t('admin.users.details.edit.action')}\n </Button>\n ) : undefined\n }\n >\n {draft ? (\n <form\n className={styles['row']}\n style={{alignItems: 'stretch', flexDirection: 'column'}}\n onSubmit={(event): void => {\n event.preventDefault();\n onUpdate?.({...(user.attributes ?? {}), ...draft});\n setDraft(null);\n }}\n >\n {Object.keys(draft).map((name: string) => (\n <TextField\n key={name}\n name={name}\n label={name}\n aria-label={name}\n value={draft[name]}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n setDraft((previous: Record<string, string> | null) => ({...previous, [name]: event.target.value}))\n }\n />\n ))}\n <div className={styles['row']} style={{justifyContent: 'flex-end'}}>\n <Button type=\"button\" variant=\"text\" disabled={isUpdating} onClick={(): void => setDraft(null)}>\n {t('admin.common.actions.cancel')}\n </Button>\n <Button type=\"submit\" loading={isUpdating} disabled={isUpdating}>\n {t('admin.users.details.edit.save')}\n </Button>\n </div>\n </form>\n ) : attributes.length > 0 ? (\n <DetailList\n items={attributes.map(([name, value]: [string, unknown]) => ({label: name, value: stringify(value)}))}\n />\n ) : (\n <span className={styles['muted']}>{t('admin.users.details.no_attributes')}</span>\n )}\n </Panel>\n <Panel title={t('admin.users.details.groups')}>\n <ChipList\n label={t('admin.users.details.groups')}\n emptyText={t('admin.users.details.no_groups')}\n items={groups.map((group: MembershipGroup) => ({id: group.id, label: group.name}))}\n />\n </Panel>\n </AdminSection>\n );\n};\n\nexport default BaseUserDetails;\n"],"mappings":"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"}
1
+ {"version":3,"file":"BaseUserDetails.js","names":["BaseUserDetails: FC<BaseUserDetailsProps>","useTranslation","styles: Record<string, string>","useAdminPartStyles","isWritable: boolean","AdminSection","Spinner","Alert","displayName: string","attributes: [string, unknown][]","editableAttributes: [string, string][]","Button","TextField"],"sources":["../../../../src/components/admin/UserDetails/BaseUserDetails.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n AccountLifecycleAction,\n resolveManagedIdentityName,\n ManagedUser,\n MembershipGroup,\n Preferences,\n} from '@thunderid/browser';\nimport {ChangeEvent, FC, ReactElement, ReactNode, useState} from 'react';\nimport useTranslation from '../../../hooks/useTranslation';\nimport Alert from '../../primitives/Alert/Alert';\nimport {Avatar} from '../../primitives/Avatar/Avatar';\nimport Button from '../../primitives/Button/Button';\nimport Spinner from '../../primitives/Spinner/Spinner';\nimport TextField from '../../primitives/TextField/TextField';\nimport {AccessStatusBadge, AccountLifecycleButtons} from '../shared/AccountLifecycleParts';\nimport {ChipList, ConfirmButton, DetailList, Panel} from '../shared/AdminParts';\nimport AdminSection from '../shared/AdminSection';\nimport useAdminPartStyles from '../shared/useAdminPartStyles';\n\n/**\n * What {@link BaseUserDetails} hands its `children` render function, so the user can be shown with any UI.\n */\nexport interface BaseUserDetailsRenderProps {\n /**\n * The user's attributes, without the hidden ones.\n */\n attributes: Record<string, unknown>;\n /**\n * The user's display name, or an empty string while there is no user.\n */\n displayName: string;\n error: string | null;\n groups: MembershipGroup[];\n isDeleting: boolean;\n isLoading: boolean;\n isRunningLifecycleAction: boolean;\n isUpdating: boolean;\n /**\n * The account lifecycle actions offered for the user. Empty when none is allowed.\n */\n lifecycleActions: AccountLifecycleAction[];\n /**\n * Deletes the user. Undefined when deletion is not allowed, including for read-only users.\n */\n onDelete?: () => void;\n /**\n * Runs an account lifecycle action, with the operator's note on a suspension. Undefined when none is\n * allowed.\n */\n onLifecycleAction?: (action: AccountLifecycleAction, operatorNote?: string) => void;\n /**\n * Saves the given attributes. Undefined when editing is not allowed, including for read-only users.\n */\n onUpdate?: (attributes: Record<string, unknown>) => void;\n user?: ManagedUser;\n}\n\nexport interface BaseUserDetailsProps {\n /**\n * Controls rendered next to the user's name.\n */\n actions?: ReactNode;\n /**\n * Renders custom UI in place of the default view. Receives the user, their visible attributes and\n * groups, the loading and error state, and the delete and update handlers.\n */\n children?: (props: BaseUserDetailsRenderProps) => ReactNode;\n className?: string;\n error?: string | null;\n /**\n * The groups the user belongs to.\n */\n groups?: MembershipGroup[];\n /**\n * Attribute names that are never shown, such as credentials.\n * @default ['password']\n */\n hiddenAttributes?: string[];\n isDeleting?: boolean;\n isLoading?: boolean;\n isRunningLifecycleAction?: boolean;\n isUpdating?: boolean;\n /**\n * The account lifecycle actions to offer (suspend, unsuspend, unlock), shown only with\n * `onLifecycleAction`. They change only runtime state, so they apply to read-only users too.\n */\n lifecycleActions?: AccountLifecycleAction[];\n /**\n * Deletes the user. The delete action is hidden when omitted.\n */\n onDelete?: () => void;\n /**\n * Runs an account lifecycle action. Suspending and unsuspending ask for confirmation first, and a\n * suspension takes an optional operator note.\n */\n onLifecycleAction?: (action: AccountLifecycleAction, operatorNote?: string) => void;\n /**\n * Saves edited attributes. Text attributes become editable only when set. Receives every\n * attribute, edited or not.\n */\n onUpdate?: (attributes: Record<string, unknown>) => void;\n preferences?: Preferences;\n user?: ManagedUser;\n}\n\nconst stringify = (value: unknown): string => {\n if (value === null || value === undefined) {\n return '';\n }\n\n return typeof value === 'object' ? JSON.stringify(value) : String(value as string | number | boolean);\n};\n\n/**\n * Shows a user's attributes, type, organization unit and groups. Holds no data of its own: pass the\n * user and handle deletion.\n */\nconst BaseUserDetails: FC<BaseUserDetailsProps> = ({\n actions,\n children,\n className,\n error = null,\n groups = [],\n hiddenAttributes = ['password'],\n isDeleting = false,\n isLoading = false,\n isRunningLifecycleAction = false,\n isUpdating = false,\n lifecycleActions = [],\n onDelete,\n onLifecycleAction,\n onUpdate,\n preferences,\n user,\n}: BaseUserDetailsProps): ReactElement => {\n const {t} = useTranslation(preferences?.i18n);\n const styles: Record<string, string> = useAdminPartStyles();\n const [draft, setDraft] = useState<Record<string, string> | null>(null);\n\n if (children) {\n const isWritable: boolean = Boolean(user) && !user?.isReadOnly;\n\n return (\n <div className={className}>\n {children({\n attributes: Object.fromEntries(\n Object.entries(user?.attributes ?? {}).filter(\n ([name]: [string, unknown]) => !hiddenAttributes.includes(name),\n ),\n ),\n displayName: user ? resolveManagedIdentityName(user) : '',\n error,\n groups,\n isDeleting,\n isLoading,\n isRunningLifecycleAction,\n isUpdating,\n lifecycleActions: onLifecycleAction && user ? lifecycleActions : [],\n onDelete: isWritable ? onDelete : undefined,\n onLifecycleAction: user ? onLifecycleAction : undefined,\n onUpdate: isWritable ? onUpdate : undefined,\n user,\n })}\n </div>\n );\n }\n\n if (isLoading && !user) {\n return (\n <AdminSection block=\"user-details\" className={className} preferences={preferences}>\n <span className={styles['muted']} role=\"status\">\n <Spinner size=\"small\" /> {t('admin.common.loading')}\n </span>\n </AdminSection>\n );\n }\n\n if (!user) {\n return (\n <AdminSection block=\"user-details\" className={className} preferences={preferences}>\n <Alert variant=\"error\" role=\"alert\">\n {error ?? t('admin.common.errors.not_found')}\n </Alert>\n </AdminSection>\n );\n }\n\n const displayName: string = resolveManagedIdentityName(user);\n const attributes: [string, unknown][] = Object.entries(user.attributes ?? {}).filter(\n ([name]: [string, unknown]) => !hiddenAttributes.includes(name),\n );\n const editableAttributes: [string, string][] = attributes.filter(\n (entry: [string, unknown]): entry is [string, string] => typeof entry[1] === 'string',\n );\n\n return (\n <AdminSection\n block=\"user-details\"\n className={className}\n title={displayName}\n description={t('admin.users.details.subtitle', {type: user.type})}\n preferences={preferences}\n actions={\n <>\n {actions}\n {onLifecycleAction && (\n <AccountLifecycleButtons\n actions={lifecycleActions}\n collectsOperatorNote\n isRunning={isRunningLifecycleAction}\n name={displayName}\n onAction={onLifecycleAction}\n />\n )}\n {onDelete && !user.isReadOnly && (\n <ConfirmButton\n confirmText={t('admin.users.details.delete.confirm', {name: displayName})}\n isLoading={isDeleting}\n onConfirm={onDelete}\n >\n {t('admin.users.details.delete.action')}\n </ConfirmButton>\n )}\n </>\n }\n >\n {error && (\n <Alert variant=\"error\" role=\"alert\">\n {error}\n </Alert>\n )}\n <div className={styles['row']}>\n <Avatar name={displayName} size={48} />\n <span className={styles['muted']}>{user.ouHandle ?? user.ouId}</span>\n <AccessStatusBadge status={user.status?.value} />\n </div>\n <Panel\n title={t('admin.users.details.attributes')}\n actions={\n onUpdate && !user.isReadOnly && !draft && editableAttributes.length > 0 ? (\n <Button\n variant=\"outline\"\n size=\"small\"\n onClick={(): void => setDraft(Object.fromEntries(editableAttributes))}\n >\n {t('admin.users.details.edit.action')}\n </Button>\n ) : undefined\n }\n >\n {draft ? (\n <form\n className={styles['row']}\n style={{alignItems: 'stretch', flexDirection: 'column'}}\n onSubmit={(event): void => {\n event.preventDefault();\n onUpdate?.({...(user.attributes ?? {}), ...draft});\n setDraft(null);\n }}\n >\n {Object.keys(draft).map((name: string) => (\n <TextField\n key={name}\n name={name}\n label={name}\n aria-label={name}\n value={draft[name]}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n setDraft((previous: Record<string, string> | null) => ({...previous, [name]: event.target.value}))\n }\n />\n ))}\n <div className={styles['row']} style={{justifyContent: 'flex-end'}}>\n <Button type=\"button\" variant=\"text\" disabled={isUpdating} onClick={(): void => setDraft(null)}>\n {t('admin.common.actions.cancel')}\n </Button>\n <Button type=\"submit\" loading={isUpdating} disabled={isUpdating}>\n {t('admin.users.details.edit.save')}\n </Button>\n </div>\n </form>\n ) : attributes.length > 0 ? (\n <DetailList\n items={attributes.map(([name, value]: [string, unknown]) => ({label: name, value: stringify(value)}))}\n />\n ) : (\n <span className={styles['muted']}>{t('admin.users.details.no_attributes')}</span>\n )}\n </Panel>\n <Panel title={t('admin.users.details.groups')}>\n <ChipList\n label={t('admin.users.details.groups')}\n emptyText={t('admin.users.details.no_groups')}\n items={groups.map((group: MembershipGroup) => ({id: group.id, label: group.name}))}\n />\n </Panel>\n </AdminSection>\n );\n};\n\nexport default BaseUserDetails;\n"],"mappings":"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"}
@@ -1,6 +1,13 @@
1
+ import { AdministrationMode } from '@thunderid/browser';
1
2
  import { FC } from 'react';
2
3
  import { BaseUserDetailsProps } from './BaseUserDetails';
3
- export type UserDetailsProps = Omit<BaseUserDetailsProps, 'error' | 'groups' | 'isDeleting' | 'isLoading' | 'isUpdating' | 'onDelete' | 'onUpdate' | 'user'> & {
4
+ export type UserDetailsProps = Omit<BaseUserDetailsProps, 'error' | 'groups' | 'isDeleting' | 'isLoading' | 'isRunningLifecycleAction' | 'isUpdating' | 'lifecycleActions' | 'onDelete' | 'onLifecycleAction' | 'onUpdate' | 'user'> & {
5
+ /**
6
+ * How the delete runs. `flow` runs the user deletion flow the server configures, which revokes the
7
+ * user's grants and ends their sessions before the record goes. It needs `baseUrl`.
8
+ * @default 'native'
9
+ */
10
+ administrationMode?: AdministrationMode;
4
11
  /**
5
12
  * Whether the user can be deleted from this view.
6
13
  * @default false
@@ -11,6 +18,13 @@ export type UserDetailsProps = Omit<BaseUserDetailsProps, 'error' | 'groups' | '
11
18
  * @default false
12
19
  */
13
20
  editable?: boolean;
21
+ /**
22
+ * Whether the user can be suspended, unsuspended and unlocked from this view. Each action runs
23
+ * through its administration flow and is offered only when the server configures that flow. Reading
24
+ * the configured flows needs a token that may read the server configuration.
25
+ * @default false
26
+ */
27
+ lifecycleActions?: boolean;
14
28
  /**
15
29
  * Called after the user has been deleted.
16
30
  */
@@ -1 +1 @@
1
- {"version":3,"file":"UserDetails.d.ts","sourceRoot":"","sources":["../../../../src/components/admin/UserDetails/UserDetails.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,EAAE,EAAe,MAAM,OAAO,CAAC;AACvC,OAAwB,EAAC,oBAAoB,EAAC,MAAM,mBAAmB,CAAC;AAWxE,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,oBAAoB,EACpB,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAClG,GAAG;IACF;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;GAOG;AACH,QAAA,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAqDrC,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"UserDetails.d.ts","sourceRoot":"","sources":["../../../../src/components/admin/UserDetails/UserDetails.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,kBAAkB,EAWnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,EAAE,EAAe,MAAM,OAAO,CAAC;AACvC,OAAwB,EAAC,oBAAoB,EAAC,MAAM,mBAAmB,CAAC;AAYxE,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,oBAAoB,EAClB,OAAO,GACP,QAAQ,GACR,YAAY,GACZ,WAAW,GACX,0BAA0B,GAC1B,YAAY,GACZ,kBAAkB,GAClB,UAAU,GACV,mBAAmB,GACnB,UAAU,GACV,MAAM,CACT,GAAG;IACF;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;GAOG;AACH,QAAA,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAoErC,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -3,6 +3,7 @@ import useManagementEndpoint_default from "../../../hooks/management/useManageme
3
3
  import useResourceQuery_default from "../../../hooks/management/useResourceQuery.js";
4
4
  import useResourceMutation_default from "../../../hooks/management/useResourceMutation.js";
5
5
  import BaseUserDetails_default from "./BaseUserDetails.js";
6
+ import useAccountLifecycle_default from "../../../hooks/management/useAccountLifecycle.js";
6
7
  import { GroupQueryKeys, UserQueryKeys, deleteUser, getUser, getUserGroups, toManagementErrorMessage, updateUser } from "@thunderid/browser";
7
8
  import { jsx } from "react/jsx-runtime";
8
9
 
@@ -15,7 +16,7 @@ import { jsx } from "react/jsx-runtime";
15
16
  * <UserDetails userId={userId} deletable onDeleted={() => navigate('/users')} />
16
17
  * ```
17
18
  */
18
- const UserDetails = ({ deletable = false, editable = false, onDeleted, preferences, userId,...rest }) => {
19
+ const UserDetails = ({ administrationMode, deletable = false, editable = false, lifecycleActions = false, onDeleted, preferences, userId,...rest }) => {
19
20
  const { t } = useTranslation_default(preferences?.i18n);
20
21
  const endpoint = useManagementEndpoint_default("users");
21
22
  const user = useResourceQuery_default([UserQueryKeys.USER, userId], (fetcher) => getUser({
@@ -36,6 +37,7 @@ const UserDetails = ({ deletable = false, editable = false, onDeleted, preferenc
36
37
  }), { enabled: Boolean(userId) });
37
38
  const deletion = useResourceMutation_default((id, fetcher) => deleteUser({
38
39
  ...endpoint,
40
+ administrationMode,
39
41
  fetcher,
40
42
  userId: id
41
43
  }), () => [[UserQueryKeys.USERS]], { onSuccess: onDeleted });
@@ -45,13 +47,23 @@ const UserDetails = ({ deletable = false, editable = false, onDeleted, preferenc
45
47
  payload: data,
46
48
  userId: id
47
49
  }), ({ userId: id }) => [[UserQueryKeys.USER, id], [UserQueryKeys.USERS]]);
50
+ const lifecycle = useAccountLifecycle_default({
51
+ enabled: lifecycleActions,
52
+ invalidatedKeys: [[UserQueryKeys.USER, userId], [UserQueryKeys.USERS]],
53
+ kind: "user",
54
+ status: user.data?.status?.value,
55
+ subject: userId
56
+ });
48
57
  return /* @__PURE__ */ jsx(BaseUserDetails_default, {
49
58
  user: user.data,
50
59
  groups: groups.data?.groups,
51
60
  isLoading: user.isLoading,
52
- error: toManagementErrorMessage(t, user.error, "admin.users.details.error") ?? toManagementErrorMessage(t, deletion.error, "admin.users.details.delete.error") ?? toManagementErrorMessage(t, update.error, "admin.users.details.edit.error"),
61
+ error: toManagementErrorMessage(t, user.error, "admin.users.details.error") ?? toManagementErrorMessage(t, deletion.error, "admin.users.details.delete.error") ?? toManagementErrorMessage(t, update.error, "admin.users.details.edit.error") ?? toManagementErrorMessage(t, lifecycle.error, "admin.common.lifecycle.error") ?? toManagementErrorMessage(t, lifecycle.loadError, "admin.common.lifecycle.load_error"),
53
62
  isDeleting: deletion.isLoading,
54
63
  onDelete: deletable ? () => void deletion.mutate(userId) : void 0,
64
+ lifecycleActions: lifecycle.actions,
65
+ isRunningLifecycleAction: lifecycle.isRunning,
66
+ onLifecycleAction: lifecycleActions ? lifecycle.run : void 0,
55
67
  isUpdating: update.isLoading,
56
68
  onUpdate: editable && user.data ? (attributes) => void update.mutate({
57
69
  data: {
@@ -1 +1 @@
1
- {"version":3,"file":"UserDetails.js","names":["UserDetails: FC<UserDetailsProps>","useTranslation","endpoint: ManagementEndpoint","useManagementEndpoint","user: ResourceQueryResult<ManagedUser>","useResourceQuery","groups: ResourceQueryResult<MembershipGroupListResponse>","deletion: ResourceMutationResult<void, string>","useResourceMutation","update: ResourceMutationResult<ManagedUser, UpdateUserVariables>","BaseUserDetails"],"sources":["../../../../src/components/admin/UserDetails/UserDetails.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n GroupQueryKeys,\n ManagedUser,\n MembershipGroupListResponse,\n UpdateManagedUserRequest,\n UserQueryKeys,\n deleteUser,\n getUser,\n getUserGroups,\n toManagementErrorMessage,\n updateUser,\n} from '@thunderid/browser';\nimport {FC, ReactElement} from 'react';\nimport BaseUserDetails, {BaseUserDetailsProps} from './BaseUserDetails';\nimport useManagementEndpoint, {ManagementEndpoint} from '../../../hooks/management/useManagementEndpoint';\nimport useResourceMutation, {ResourceMutationResult} from '../../../hooks/management/useResourceMutation';\nimport useResourceQuery, {ResourceQueryResult} from '../../../hooks/management/useResourceQuery';\nimport useTranslation from '../../../hooks/useTranslation';\n\ninterface UpdateUserVariables {\n data: UpdateManagedUserRequest;\n userId: string;\n}\n\nexport type UserDetailsProps = Omit<\n BaseUserDetailsProps,\n 'error' | 'groups' | 'isDeleting' | 'isLoading' | 'isUpdating' | 'onDelete' | 'onUpdate' | 'user'\n> & {\n /**\n * Whether the user can be deleted from this view.\n * @default false\n */\n deletable?: boolean;\n /**\n * Whether the user's text attributes can be edited from this view.\n * @default false\n */\n editable?: boolean;\n /**\n * Called after the user has been deleted.\n */\n onDeleted?: () => void;\n userId: string;\n};\n\n/**\n * Shows a user and the groups they belong to, and optionally lets the signed-in user delete them.\n *\n * @example\n * ```tsx\n * <UserDetails userId={userId} deletable onDeleted={() => navigate('/users')} />\n * ```\n */\nconst UserDetails: FC<UserDetailsProps> = ({\n deletable = false,\n editable = false,\n onDeleted,\n preferences,\n userId,\n ...rest\n}: UserDetailsProps): ReactElement => {\n const {t} = useTranslation(preferences?.i18n);\n const endpoint: ManagementEndpoint = useManagementEndpoint('users');\n const user: ResourceQueryResult<ManagedUser> = useResourceQuery(\n [UserQueryKeys.USER, userId],\n (fetcher) => getUser({...endpoint, fetcher, userId}),\n {enabled: Boolean(userId)},\n );\n const groups: ResourceQueryResult<MembershipGroupListResponse> = useResourceQuery(\n [GroupQueryKeys.MEMBERSHIPS, 'user', userId, {limit: 100}],\n (fetcher) => getUserGroups({...endpoint, fetcher, limit: 100, userId}),\n {enabled: Boolean(userId)},\n );\n const deletion: ResourceMutationResult<void, string> = useResourceMutation(\n (id: string, fetcher) => deleteUser({...endpoint, fetcher, userId: id}),\n () => [[UserQueryKeys.USERS]],\n {onSuccess: onDeleted},\n );\n const update: ResourceMutationResult<ManagedUser, UpdateUserVariables> = useResourceMutation(\n ({data, userId: id}: UpdateUserVariables, fetcher) => updateUser({...endpoint, fetcher, payload: data, userId: id}),\n ({userId: id}: UpdateUserVariables) => [[UserQueryKeys.USER, id], [UserQueryKeys.USERS]],\n );\n\n return (\n <BaseUserDetails\n user={user.data}\n groups={groups.data?.groups}\n isLoading={user.isLoading}\n error={\n toManagementErrorMessage(t, user.error, 'admin.users.details.error') ??\n toManagementErrorMessage(t, deletion.error, 'admin.users.details.delete.error') ??\n toManagementErrorMessage(t, update.error, 'admin.users.details.edit.error')\n }\n isDeleting={deletion.isLoading}\n onDelete={deletable ? (): void => void deletion.mutate(userId) : undefined}\n isUpdating={update.isLoading}\n onUpdate={\n editable && user.data\n ? (attributes: Record<string, unknown>): void =>\n void update.mutate({data: {attributes, ouId: user.data!.ouId, type: user.data!.type}, userId})\n : undefined\n }\n preferences={preferences}\n {...rest}\n />\n );\n};\n\nexport default UserDetails;\n"],"mappings":";;;;;;;;;;;;;;;;;AAwDA,MAAMA,eAAqC,EACzC,YAAY,OACZ,WAAW,OACX,WACA,aACA,OACA,GAAG,WACiC;CACpC,MAAM,EAAC,MAAKC,uBAAe,aAAa,KAAK;CAC7C,MAAMC,WAA+BC,8BAAsB,QAAQ;CACnE,MAAMC,OAAyCC,yBAC7C,CAAC,cAAc,MAAM,OAAO,GAC3B,YAAY,QAAQ;EAAC,GAAG;EAAU;EAAS;EAAO,CAAC,EACpD,EAAC,SAAS,QAAQ,OAAO,EAAC,CAC3B;CACD,MAAMC,SAA2DD,yBAC/D;EAAC,eAAe;EAAa;EAAQ;EAAQ,EAAC,OAAO,KAAI;EAAC,GACzD,YAAY,cAAc;EAAC,GAAG;EAAU;EAAS,OAAO;EAAK;EAAO,CAAC,EACtE,EAAC,SAAS,QAAQ,OAAO,EAAC,CAC3B;CACD,MAAME,WAAiDC,6BACpD,IAAY,YAAY,WAAW;EAAC,GAAG;EAAU;EAAS,QAAQ;EAAG,CAAC,QACjE,CAAC,CAAC,cAAc,MAAM,CAAC,EAC7B,EAAC,WAAW,WAAU,CACvB;CACD,MAAMC,SAAmED,6BACtE,EAAC,MAAM,QAAQ,MAA0B,YAAY,WAAW;EAAC,GAAG;EAAU;EAAS,SAAS;EAAM,QAAQ;EAAG,CAAC,GAClH,EAAC,QAAQ,SAA6B,CAAC,CAAC,cAAc,MAAM,GAAG,EAAE,CAAC,cAAc,MAAM,CAAC,CACzF;AAED,QACE,oBAACE;EACC,MAAM,KAAK;EACX,QAAQ,OAAO,MAAM;EACrB,WAAW,KAAK;EAChB,OACE,yBAAyB,GAAG,KAAK,OAAO,4BAA4B,IACpE,yBAAyB,GAAG,SAAS,OAAO,mCAAmC,IAC/E,yBAAyB,GAAG,OAAO,OAAO,iCAAiC;EAE7E,YAAY,SAAS;EACrB,UAAU,kBAAwB,KAAK,SAAS,OAAO,OAAO,GAAG;EACjE,YAAY,OAAO;EACnB,UACE,YAAY,KAAK,QACZ,eACC,KAAK,OAAO,OAAO;GAAC,MAAM;IAAC;IAAY,MAAM,KAAK,KAAM;IAAM,MAAM,KAAK,KAAM;IAAK;GAAE;GAAO,CAAC,GAChG;EAEO;EACb,GAAI;GACJ;;AAIN,0BAAe"}
1
+ {"version":3,"file":"UserDetails.js","names":["UserDetails: FC<UserDetailsProps>","useTranslation","endpoint: ManagementEndpoint","useManagementEndpoint","user: ResourceQueryResult<ManagedUser>","useResourceQuery","groups: ResourceQueryResult<MembershipGroupListResponse>","deletion: ResourceMutationResult<void, string>","useResourceMutation","update: ResourceMutationResult<ManagedUser, UpdateUserVariables>","lifecycle: AccountLifecycleState","useAccountLifecycle","BaseUserDetails"],"sources":["../../../../src/components/admin/UserDetails/UserDetails.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n AdministrationMode,\n GroupQueryKeys,\n ManagedUser,\n MembershipGroupListResponse,\n UpdateManagedUserRequest,\n UserQueryKeys,\n deleteUser,\n getUser,\n getUserGroups,\n toManagementErrorMessage,\n updateUser,\n} from '@thunderid/browser';\nimport {FC, ReactElement} from 'react';\nimport BaseUserDetails, {BaseUserDetailsProps} from './BaseUserDetails';\nimport useAccountLifecycle, {AccountLifecycleState} from '../../../hooks/management/useAccountLifecycle';\nimport useManagementEndpoint, {ManagementEndpoint} from '../../../hooks/management/useManagementEndpoint';\nimport useResourceMutation, {ResourceMutationResult} from '../../../hooks/management/useResourceMutation';\nimport useResourceQuery, {ResourceQueryResult} from '../../../hooks/management/useResourceQuery';\nimport useTranslation from '../../../hooks/useTranslation';\n\ninterface UpdateUserVariables {\n data: UpdateManagedUserRequest;\n userId: string;\n}\n\nexport type UserDetailsProps = Omit<\n BaseUserDetailsProps,\n | 'error'\n | 'groups'\n | 'isDeleting'\n | 'isLoading'\n | 'isRunningLifecycleAction'\n | 'isUpdating'\n | 'lifecycleActions'\n | 'onDelete'\n | 'onLifecycleAction'\n | 'onUpdate'\n | 'user'\n> & {\n /**\n * How the delete runs. `flow` runs the user deletion flow the server configures, which revokes the\n * user's grants and ends their sessions before the record goes. It needs `baseUrl`.\n * @default 'native'\n */\n administrationMode?: AdministrationMode;\n /**\n * Whether the user can be deleted from this view.\n * @default false\n */\n deletable?: boolean;\n /**\n * Whether the user's text attributes can be edited from this view.\n * @default false\n */\n editable?: boolean;\n /**\n * Whether the user can be suspended, unsuspended and unlocked from this view. Each action runs\n * through its administration flow and is offered only when the server configures that flow. Reading\n * the configured flows needs a token that may read the server configuration.\n * @default false\n */\n lifecycleActions?: boolean;\n /**\n * Called after the user has been deleted.\n */\n onDeleted?: () => void;\n userId: string;\n};\n\n/**\n * Shows a user and the groups they belong to, and optionally lets the signed-in user delete them.\n *\n * @example\n * ```tsx\n * <UserDetails userId={userId} deletable onDeleted={() => navigate('/users')} />\n * ```\n */\nconst UserDetails: FC<UserDetailsProps> = ({\n administrationMode,\n deletable = false,\n editable = false,\n lifecycleActions = false,\n onDeleted,\n preferences,\n userId,\n ...rest\n}: UserDetailsProps): ReactElement => {\n const {t} = useTranslation(preferences?.i18n);\n const endpoint: ManagementEndpoint = useManagementEndpoint('users');\n const user: ResourceQueryResult<ManagedUser> = useResourceQuery(\n [UserQueryKeys.USER, userId],\n (fetcher) => getUser({...endpoint, fetcher, userId}),\n {enabled: Boolean(userId)},\n );\n const groups: ResourceQueryResult<MembershipGroupListResponse> = useResourceQuery(\n [GroupQueryKeys.MEMBERSHIPS, 'user', userId, {limit: 100}],\n (fetcher) => getUserGroups({...endpoint, fetcher, limit: 100, userId}),\n {enabled: Boolean(userId)},\n );\n const deletion: ResourceMutationResult<void, string> = useResourceMutation(\n (id: string, fetcher) => deleteUser({...endpoint, administrationMode, fetcher, userId: id}),\n () => [[UserQueryKeys.USERS]],\n {onSuccess: onDeleted},\n );\n const update: ResourceMutationResult<ManagedUser, UpdateUserVariables> = useResourceMutation(\n ({data, userId: id}: UpdateUserVariables, fetcher) => updateUser({...endpoint, fetcher, payload: data, userId: id}),\n ({userId: id}: UpdateUserVariables) => [[UserQueryKeys.USER, id], [UserQueryKeys.USERS]],\n );\n\n const lifecycle: AccountLifecycleState = useAccountLifecycle({\n enabled: lifecycleActions,\n invalidatedKeys: [[UserQueryKeys.USER, userId], [UserQueryKeys.USERS]],\n kind: 'user',\n status: user.data?.status?.value,\n subject: userId,\n });\n\n return (\n <BaseUserDetails\n user={user.data}\n groups={groups.data?.groups}\n isLoading={user.isLoading}\n error={\n toManagementErrorMessage(t, user.error, 'admin.users.details.error') ??\n toManagementErrorMessage(t, deletion.error, 'admin.users.details.delete.error') ??\n toManagementErrorMessage(t, update.error, 'admin.users.details.edit.error') ??\n toManagementErrorMessage(t, lifecycle.error, 'admin.common.lifecycle.error') ??\n toManagementErrorMessage(t, lifecycle.loadError, 'admin.common.lifecycle.load_error')\n }\n isDeleting={deletion.isLoading}\n onDelete={deletable ? (): void => void deletion.mutate(userId) : undefined}\n lifecycleActions={lifecycle.actions}\n isRunningLifecycleAction={lifecycle.isRunning}\n onLifecycleAction={lifecycleActions ? lifecycle.run : undefined}\n isUpdating={update.isLoading}\n onUpdate={\n editable && user.data\n ? (attributes: Record<string, unknown>): void =>\n void update.mutate({data: {attributes, ouId: user.data!.ouId, type: user.data!.type}, userId})\n : undefined\n }\n preferences={preferences}\n {...rest}\n />\n );\n};\n\nexport default UserDetails;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiFA,MAAMA,eAAqC,EACzC,oBACA,YAAY,OACZ,WAAW,OACX,mBAAmB,OACnB,WACA,aACA,OACA,GAAG,WACiC;CACpC,MAAM,EAAC,MAAKC,uBAAe,aAAa,KAAK;CAC7C,MAAMC,WAA+BC,8BAAsB,QAAQ;CACnE,MAAMC,OAAyCC,yBAC7C,CAAC,cAAc,MAAM,OAAO,GAC3B,YAAY,QAAQ;EAAC,GAAG;EAAU;EAAS;EAAO,CAAC,EACpD,EAAC,SAAS,QAAQ,OAAO,EAAC,CAC3B;CACD,MAAMC,SAA2DD,yBAC/D;EAAC,eAAe;EAAa;EAAQ;EAAQ,EAAC,OAAO,KAAI;EAAC,GACzD,YAAY,cAAc;EAAC,GAAG;EAAU;EAAS,OAAO;EAAK;EAAO,CAAC,EACtE,EAAC,SAAS,QAAQ,OAAO,EAAC,CAC3B;CACD,MAAME,WAAiDC,6BACpD,IAAY,YAAY,WAAW;EAAC,GAAG;EAAU;EAAoB;EAAS,QAAQ;EAAG,CAAC,QACrF,CAAC,CAAC,cAAc,MAAM,CAAC,EAC7B,EAAC,WAAW,WAAU,CACvB;CACD,MAAMC,SAAmED,6BACtE,EAAC,MAAM,QAAQ,MAA0B,YAAY,WAAW;EAAC,GAAG;EAAU;EAAS,SAAS;EAAM,QAAQ;EAAG,CAAC,GAClH,EAAC,QAAQ,SAA6B,CAAC,CAAC,cAAc,MAAM,GAAG,EAAE,CAAC,cAAc,MAAM,CAAC,CACzF;CAED,MAAME,YAAmCC,4BAAoB;EAC3D,SAAS;EACT,iBAAiB,CAAC,CAAC,cAAc,MAAM,OAAO,EAAE,CAAC,cAAc,MAAM,CAAC;EACtE,MAAM;EACN,QAAQ,KAAK,MAAM,QAAQ;EAC3B,SAAS;EACV,CAAC;AAEF,QACE,oBAACC;EACC,MAAM,KAAK;EACX,QAAQ,OAAO,MAAM;EACrB,WAAW,KAAK;EAChB,OACE,yBAAyB,GAAG,KAAK,OAAO,4BAA4B,IACpE,yBAAyB,GAAG,SAAS,OAAO,mCAAmC,IAC/E,yBAAyB,GAAG,OAAO,OAAO,iCAAiC,IAC3E,yBAAyB,GAAG,UAAU,OAAO,+BAA+B,IAC5E,yBAAyB,GAAG,UAAU,WAAW,oCAAoC;EAEvF,YAAY,SAAS;EACrB,UAAU,kBAAwB,KAAK,SAAS,OAAO,OAAO,GAAG;EACjE,kBAAkB,UAAU;EAC5B,0BAA0B,UAAU;EACpC,mBAAmB,mBAAmB,UAAU,MAAM;EACtD,YAAY,OAAO;EACnB,UACE,YAAY,KAAK,QACZ,eACC,KAAK,OAAO,OAAO;GAAC,MAAM;IAAC;IAAY,MAAM,KAAK,KAAM;IAAM,MAAM,KAAK,KAAM;IAAK;GAAE;GAAO,CAAC,GAChG;EAEO;EACb,GAAI;GACJ;;AAIN,0BAAe"}
@@ -0,0 +1,32 @@
1
+ import { AccessStatusValue, AccountLifecycleAction } from '@thunderid/browser';
2
+ import { FC } from 'react';
3
+ export interface AccessStatusBadgeProps {
4
+ status?: AccessStatusValue;
5
+ }
6
+ /**
7
+ * The translated access status of an identity, or its raw value when the status is one this SDK does
8
+ * not know. Renders nothing when the server reports no status.
9
+ */
10
+ export declare const AccessStatusBadge: FC<AccessStatusBadgeProps>;
11
+ export interface AccountLifecycleButtonsProps {
12
+ /**
13
+ * The actions to offer, most expected first.
14
+ */
15
+ actions: AccountLifecycleAction[];
16
+ /**
17
+ * Whether a suspension asks for an optional operator note. The note is recorded by the flow.
18
+ */
19
+ collectsOperatorNote?: boolean;
20
+ isRunning?: boolean;
21
+ /**
22
+ * Name of the identity, already resolved, used in the confirmation question.
23
+ */
24
+ name: string;
25
+ onAction: (action: AccountLifecycleAction, operatorNote?: string) => void;
26
+ }
27
+ /**
28
+ * One button per account lifecycle action. Suspending and unsuspending ask for confirmation inline;
29
+ * unlocking is remedial and runs straight away.
30
+ */
31
+ export declare const AccountLifecycleButtons: FC<AccountLifecycleButtonsProps>;
32
+ //# sourceMappingURL=AccountLifecycleParts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccountLifecycleParts.d.ts","sourceRoot":"","sources":["../../../../src/components/admin/shared/AccountLifecycleParts.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAC,iBAAiB,EAAE,sBAAsB,EAAC,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAc,EAAE,EAAyB,MAAM,OAAO,CAAC;AAW9D,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAiBxD,CAAC;AAEF,MAAM,WAAW,4BAA4B;IAC3C;;OAEG;IACH,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC;;OAEG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,CAAC,MAAM,EAAE,sBAAsB,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3E;AAED;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,EAAE,CAAC,4BAA4B,CAkFpE,CAAC"}
@@ -0,0 +1,101 @@
1
+ import useTranslation_default from "../../../hooks/useTranslation.js";
2
+ import Button_default from "../../primitives/Button/Button.js";
3
+ import TextField_default from "../../primitives/TextField/TextField.js";
4
+ import useAdminPartStyles_default from "./useAdminPartStyles.js";
5
+ import { useState } from "react";
6
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
+
8
+ //#region src/components/admin/shared/AccountLifecycleParts.tsx
9
+ /**
10
+ * Matches the server's limit on an operator note.
11
+ */
12
+ const OPERATOR_NOTE_MAX_LENGTH = 100;
13
+ /**
14
+ * The translated access status of an identity, or its raw value when the status is one this SDK does
15
+ * not know. Renders nothing when the server reports no status.
16
+ */
17
+ const AccessStatusBadge = ({ status }) => {
18
+ const styles = useAdminPartStyles_default();
19
+ const { t } = useTranslation_default();
20
+ if (!status) return null;
21
+ const labels = {
22
+ ACTIVE: t("admin.common.status.active"),
23
+ LOCKED: t("admin.common.status.locked"),
24
+ SUSPENDED: t("admin.common.status.suspended")
25
+ };
26
+ return /* @__PURE__ */ jsx("span", {
27
+ className: styles["chip"],
28
+ children: labels[status] ?? status
29
+ });
30
+ };
31
+ /**
32
+ * One button per account lifecycle action. Suspending and unsuspending ask for confirmation inline;
33
+ * unlocking is remedial and runs straight away.
34
+ */
35
+ const AccountLifecycleButtons = ({ actions, collectsOperatorNote = false, isRunning = false, name, onAction }) => {
36
+ const styles = useAdminPartStyles_default();
37
+ const { t } = useTranslation_default();
38
+ const [confirming, setConfirming] = useState(null);
39
+ const [operatorNote, setOperatorNote] = useState("");
40
+ if (actions.length === 0) return null;
41
+ const labels = {
42
+ suspend: t("admin.common.lifecycle.suspend"),
43
+ unlock: t("admin.common.lifecycle.unlock"),
44
+ unsuspend: t("admin.common.lifecycle.unsuspend")
45
+ };
46
+ if (confirming && actions.includes(confirming)) {
47
+ const question = confirming === "suspend" ? t("admin.common.lifecycle.suspend_confirm", { name }) : t("admin.common.lifecycle.unsuspend_confirm", { name });
48
+ const withNote = collectsOperatorNote && confirming === "suspend";
49
+ const close = () => {
50
+ setConfirming(null);
51
+ setOperatorNote("");
52
+ };
53
+ return /* @__PURE__ */ jsxs("span", {
54
+ className: styles["confirm"],
55
+ role: "group",
56
+ "aria-label": question,
57
+ children: [
58
+ /* @__PURE__ */ jsx("span", { children: question }),
59
+ withNote && /* @__PURE__ */ jsx(TextField_default, {
60
+ name: "operatorNote",
61
+ label: t("admin.common.lifecycle.operator_note"),
62
+ "aria-label": t("admin.common.lifecycle.operator_note"),
63
+ value: operatorNote,
64
+ maxLength: OPERATOR_NOTE_MAX_LENGTH,
65
+ disabled: isRunning,
66
+ onChange: (event) => setOperatorNote(event.target.value)
67
+ }),
68
+ /* @__PURE__ */ jsx(Button_default, {
69
+ variant: "text",
70
+ size: "small",
71
+ disabled: isRunning,
72
+ onClick: close,
73
+ children: t("admin.common.actions.cancel")
74
+ }),
75
+ /* @__PURE__ */ jsx(Button_default, {
76
+ color: confirming === "suspend" ? "error" : "primary",
77
+ size: "small",
78
+ loading: isRunning,
79
+ disabled: isRunning,
80
+ onClick: () => {
81
+ onAction(confirming, withNote ? operatorNote.trim() || void 0 : void 0);
82
+ close();
83
+ },
84
+ children: labels[confirming]
85
+ })
86
+ ]
87
+ });
88
+ }
89
+ return /* @__PURE__ */ jsx(Fragment$1, { children: actions.map((action) => /* @__PURE__ */ jsx(Button_default, {
90
+ variant: "outline",
91
+ color: action === "suspend" ? "error" : "primary",
92
+ disabled: isRunning,
93
+ loading: isRunning && action === "unlock",
94
+ onClick: () => action === "unlock" ? onAction(action) : setConfirming(action),
95
+ children: labels[action]
96
+ }, action)) });
97
+ };
98
+
99
+ //#endregion
100
+ export { AccessStatusBadge, AccountLifecycleButtons };
101
+ //# sourceMappingURL=AccountLifecycleParts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AccountLifecycleParts.js","names":["AccessStatusBadge: FC<AccessStatusBadgeProps>","styles: Record<string, string>","useAdminPartStyles","useTranslation","labels: Record<AccessStatusValue, string>","AccountLifecycleButtons: FC<AccountLifecycleButtonsProps>","labels: Record<AccountLifecycleAction, string>","question: string","withNote: boolean","TextField","Button"],"sources":["../../../../src/components/admin/shared/AccountLifecycleParts.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {AccessStatusValue, AccountLifecycleAction} from '@thunderid/browser';\nimport {ChangeEvent, FC, ReactElement, useState} from 'react';\nimport useAdminPartStyles from './useAdminPartStyles';\nimport useTranslation from '../../../hooks/useTranslation';\nimport Button from '../../primitives/Button/Button';\nimport TextField from '../../primitives/TextField/TextField';\n\n/**\n * Matches the server's limit on an operator note.\n */\nconst OPERATOR_NOTE_MAX_LENGTH = 100;\n\nexport interface AccessStatusBadgeProps {\n status?: AccessStatusValue;\n}\n\n/**\n * The translated access status of an identity, or its raw value when the status is one this SDK does\n * not know. Renders nothing when the server reports no status.\n */\nexport const AccessStatusBadge: FC<AccessStatusBadgeProps> = ({\n status,\n}: AccessStatusBadgeProps): ReactElement | null => {\n const styles: Record<string, string> = useAdminPartStyles();\n const {t} = useTranslation();\n\n if (!status) {\n return null;\n }\n\n const labels: Record<AccessStatusValue, string> = {\n ACTIVE: t('admin.common.status.active'),\n LOCKED: t('admin.common.status.locked'),\n SUSPENDED: t('admin.common.status.suspended'),\n };\n\n return <span className={styles['chip']}>{labels[status] ?? status}</span>;\n};\n\nexport interface AccountLifecycleButtonsProps {\n /**\n * The actions to offer, most expected first.\n */\n actions: AccountLifecycleAction[];\n /**\n * Whether a suspension asks for an optional operator note. The note is recorded by the flow.\n */\n collectsOperatorNote?: boolean;\n isRunning?: boolean;\n /**\n * Name of the identity, already resolved, used in the confirmation question.\n */\n name: string;\n onAction: (action: AccountLifecycleAction, operatorNote?: string) => void;\n}\n\n/**\n * One button per account lifecycle action. Suspending and unsuspending ask for confirmation inline;\n * unlocking is remedial and runs straight away.\n */\nexport const AccountLifecycleButtons: FC<AccountLifecycleButtonsProps> = ({\n actions,\n collectsOperatorNote = false,\n isRunning = false,\n name,\n onAction,\n}: AccountLifecycleButtonsProps): ReactElement | null => {\n const styles: Record<string, string> = useAdminPartStyles();\n const {t} = useTranslation();\n const [confirming, setConfirming] = useState<AccountLifecycleAction | null>(null);\n const [operatorNote, setOperatorNote] = useState<string>('');\n\n if (actions.length === 0) {\n return null;\n }\n\n const labels: Record<AccountLifecycleAction, string> = {\n suspend: t('admin.common.lifecycle.suspend'),\n unlock: t('admin.common.lifecycle.unlock'),\n unsuspend: t('admin.common.lifecycle.unsuspend'),\n };\n\n if (confirming && actions.includes(confirming)) {\n const question: string =\n confirming === 'suspend'\n ? t('admin.common.lifecycle.suspend_confirm', {name})\n : t('admin.common.lifecycle.unsuspend_confirm', {name});\n const withNote: boolean = collectsOperatorNote && confirming === 'suspend';\n const close = (): void => {\n setConfirming(null);\n setOperatorNote('');\n };\n\n return (\n <span className={styles['confirm']} role=\"group\" aria-label={question}>\n <span>{question}</span>\n {withNote && (\n <TextField\n name=\"operatorNote\"\n label={t('admin.common.lifecycle.operator_note')}\n aria-label={t('admin.common.lifecycle.operator_note')}\n value={operatorNote}\n maxLength={OPERATOR_NOTE_MAX_LENGTH}\n disabled={isRunning}\n onChange={(event: ChangeEvent<HTMLInputElement>): void => setOperatorNote(event.target.value)}\n />\n )}\n <Button variant=\"text\" size=\"small\" disabled={isRunning} onClick={close}>\n {t('admin.common.actions.cancel')}\n </Button>\n <Button\n color={confirming === 'suspend' ? 'error' : 'primary'}\n size=\"small\"\n loading={isRunning}\n disabled={isRunning}\n onClick={(): void => {\n onAction(confirming, withNote ? operatorNote.trim() || undefined : undefined);\n close();\n }}\n >\n {labels[confirming]}\n </Button>\n </span>\n );\n }\n\n return (\n <>\n {actions.map((action: AccountLifecycleAction) => (\n <Button\n key={action}\n variant=\"outline\"\n color={action === 'suspend' ? 'error' : 'primary'}\n disabled={isRunning}\n loading={isRunning && action === 'unlock'}\n onClick={(): void => (action === 'unlock' ? onAction(action) : setConfirming(action))}\n >\n {labels[action]}\n </Button>\n ))}\n </>\n );\n};\n"],"mappings":";;;;;;;;;;;AAaA,MAAM,2BAA2B;;;;;AAUjC,MAAaA,qBAAiD,EAC5D,aACiD;CACjD,MAAMC,SAAiCC,4BAAoB;CAC3D,MAAM,EAAC,MAAKC,wBAAgB;AAE5B,KAAI,CAAC,OACH,QAAO;CAGT,MAAMC,SAA4C;EAChD,QAAQ,EAAE,6BAA6B;EACvC,QAAQ,EAAE,6BAA6B;EACvC,WAAW,EAAE,gCAAgC;EAC9C;AAED,QAAO,oBAAC;EAAK,WAAW,OAAO;YAAU,OAAO,WAAW;GAAc;;;;;;AAwB3E,MAAaC,2BAA6D,EACxE,SACA,uBAAuB,OACvB,YAAY,OACZ,MACA,eACuD;CACvD,MAAMJ,SAAiCC,4BAAoB;CAC3D,MAAM,EAAC,MAAKC,wBAAgB;CAC5B,MAAM,CAAC,YAAY,iBAAiB,SAAwC,KAAK;CACjF,MAAM,CAAC,cAAc,mBAAmB,SAAiB,GAAG;AAE5D,KAAI,QAAQ,WAAW,EACrB,QAAO;CAGT,MAAMG,SAAiD;EACrD,SAAS,EAAE,iCAAiC;EAC5C,QAAQ,EAAE,gCAAgC;EAC1C,WAAW,EAAE,mCAAmC;EACjD;AAED,KAAI,cAAc,QAAQ,SAAS,WAAW,EAAE;EAC9C,MAAMC,WACJ,eAAe,YACX,EAAE,0CAA0C,EAAC,MAAK,CAAC,GACnD,EAAE,4CAA4C,EAAC,MAAK,CAAC;EAC3D,MAAMC,WAAoB,wBAAwB,eAAe;EACjE,MAAM,cAAoB;AACxB,iBAAc,KAAK;AACnB,mBAAgB,GAAG;;AAGrB,SACE,qBAAC;GAAK,WAAW,OAAO;GAAY,MAAK;GAAQ,cAAY;;IAC3D,oBAAC,oBAAM,WAAgB;IACtB,YACC,oBAACC;KACC,MAAK;KACL,OAAO,EAAE,uCAAuC;KAChD,cAAY,EAAE,uCAAuC;KACrD,OAAO;KACP,WAAW;KACX,UAAU;KACV,WAAW,UAA+C,gBAAgB,MAAM,OAAO,MAAM;MAC7F;IAEJ,oBAACC;KAAO,SAAQ;KAAO,MAAK;KAAQ,UAAU;KAAW,SAAS;eAC/D,EAAE,8BAA8B;MAC1B;IACT,oBAACA;KACC,OAAO,eAAe,YAAY,UAAU;KAC5C,MAAK;KACL,SAAS;KACT,UAAU;KACV,eAAqB;AACnB,eAAS,YAAY,WAAW,aAAa,MAAM,IAAI,SAAY,OAAU;AAC7E,aAAO;;eAGR,OAAO;MACD;;IACJ;;AAIX,QACE,4CACG,QAAQ,KAAK,WACZ,oBAACA;EAEC,SAAQ;EACR,OAAO,WAAW,YAAY,UAAU;EACxC,UAAU;EACV,SAAS,aAAa,WAAW;EACjC,eAAsB,WAAW,WAAW,SAAS,OAAO,GAAG,cAAc,OAAO;YAEnF,OAAO;IAPH,OAQE,CACT,GACD"}
@@ -1,6 +1,6 @@
1
1
  import useTranslation_default from "../../../hooks/useTranslation.js";
2
- import Checkbox_default from "../../primitives/Checkbox/Checkbox.js";
3
2
  import TextField_default from "../../primitives/TextField/TextField.js";
3
+ import Checkbox_default from "../../primitives/Checkbox/Checkbox.js";
4
4
  import useAdminPartStyles_default from "./useAdminPartStyles.js";
5
5
  import { APPLICATION_GRANT_TYPES } from "@thunderid/browser";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -1 +1 @@
1
- {"version":3,"file":"BaseAcceptInvite.d.ts","sourceRoot":"","sources":["../../../../src/components/auth/AcceptInvite/BaseAcceptInvite.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BaseAcceptInvite.d.ts","sourceRoot":"","sources":["../../../../src/components/auth/AcceptInvite/BaseAcceptInvite.tsx"],"names":[],"mappings":"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"}
@@ -9,11 +9,12 @@ import Button_default from "../../primitives/Button/Button.js";
9
9
  import Typography_default from "../../primitives/Typography/Typography.js";
10
10
  import Alert_default from "../../primitives/Alert/Alert.js";
11
11
  import Card_default from "../../primitives/Card/Card.js";
12
+ import isConsentApprovalBlocked_default from "../../../utils/isConsentApprovalBlocked.js";
12
13
  import { renderInviteUserComponents } from "../flow/AuthOptionFactory.js";
13
14
  import { useOAuthCallback } from "../../../hooks/auth/useOAuthCallback.js";
14
15
  import { initiateOAuthRedirect } from "../../../utils/oauth.js";
15
16
  import BaseAcceptInvite_styles_default from "./BaseAcceptInvite.styles.js";
16
- import { ConsentConstants, buildValidatorFromRules } from "@thunderid/browser";
17
+ import { CONSENT_INVALID_KEY_PREFIX, CONSENT_MODIFIED_KEY_PREFIX, ConsentConstants, buildValidatorFromRules, getConsentElementDecision } from "@thunderid/browser";
17
18
  import { useCallback, useContext, useEffect, useRef, useState } from "react";
18
19
  import { jsx, jsxs } from "react/jsx-runtime";
19
20
 
@@ -249,6 +250,7 @@ const BaseAcceptInvite = ({ executionId, inviteToken, onSubmit, onComplete, onEr
249
250
  const raw = currentAdditionalData["consentPrompt"];
250
251
  const purposes = typeof raw === "string" ? JSON.parse(raw) : raw.purposes || raw;
251
252
  const isDeny = component?.variant?.toLowerCase() !== "primary";
253
+ if (!isDeny && isConsentApprovalBlocked_default(purposes, inputs)) return;
252
254
  const decisions = {
253
255
  approved: !isDeny,
254
256
  ...isDeny ? { reason: ConsentConstants.REASON_USER_DENIED } : {},
@@ -260,16 +262,13 @@ const BaseAcceptInvite = ({ executionId, inviteToken, onSubmit, onComplete, onEr
260
262
  name: e.name
261
263
  })), ...(p.optional || []).map((e) => {
262
264
  const key = `__consent_opt__${p.purposeId}__${e.name}`;
263
- return {
264
- approved: !isDeny && inputs[key] === "true",
265
- name: e.name
266
- };
265
+ return getConsentElementDecision(p.purposeId, e, !isDeny && inputs[key] === "true", inputs);
267
266
  })]
268
267
  }))
269
268
  };
270
269
  inputs.consent_decisions = JSON.stringify(decisions);
271
270
  Object.keys(inputs).forEach((k) => {
272
- if (k.startsWith("__consent_opt__")) delete inputs[k];
271
+ if (k.startsWith("__consent_opt__") || k.startsWith(CONSENT_MODIFIED_KEY_PREFIX) || k.startsWith(CONSENT_INVALID_KEY_PREFIX)) delete inputs[k];
273
272
  });
274
273
  } catch {}
275
274
  const payload = {