@workos-inc/widgets 1.7.2 → 1.8.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 (214) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/cjs/api/endpoint.cjs +1 -0
  3. package/dist/cjs/api/endpoint.cjs.map +1 -1
  4. package/dist/cjs/api/endpoint.d.cts +1 -0
  5. package/dist/cjs/index.cjs +5 -2
  6. package/dist/cjs/index.cjs.map +1 -1
  7. package/dist/cjs/index.d.cts +1 -0
  8. package/dist/cjs/lib/add-mfa-dialog.cjs +133 -61
  9. package/dist/cjs/lib/add-mfa-dialog.cjs.map +1 -1
  10. package/dist/cjs/lib/admin-portal-domain-verification.cjs +41 -5
  11. package/dist/cjs/lib/admin-portal-domain-verification.cjs.map +1 -1
  12. package/dist/cjs/lib/admin-portal-sso-connection.cjs +121 -44
  13. package/dist/cjs/lib/admin-portal-sso-connection.cjs.map +1 -1
  14. package/dist/cjs/lib/api-keys/api-key-details-card.cjs +25 -3
  15. package/dist/cjs/lib/api-keys/api-key-details-card.cjs.map +1 -1
  16. package/dist/cjs/lib/api-keys/api-key-details-dialog.cjs +25 -3
  17. package/dist/cjs/lib/api-keys/api-key-details-dialog.cjs.map +1 -1
  18. package/dist/cjs/lib/api-keys/api-keys-search.cjs +13 -4
  19. package/dist/cjs/lib/api-keys/api-keys-search.cjs.map +1 -1
  20. package/dist/cjs/lib/api-keys/api-keys-table.cjs +94 -12
  21. package/dist/cjs/lib/api-keys/api-keys-table.cjs.map +1 -1
  22. package/dist/cjs/lib/api-keys/api-keys.cjs +16 -2
  23. package/dist/cjs/lib/api-keys/api-keys.cjs.map +1 -1
  24. package/dist/cjs/lib/api-keys/create-api-key.cjs +172 -20
  25. package/dist/cjs/lib/api-keys/create-api-key.cjs.map +1 -1
  26. package/dist/cjs/lib/api-keys/relative-time.cjs +12 -2
  27. package/dist/cjs/lib/api-keys/relative-time.cjs.map +1 -1
  28. package/dist/cjs/lib/api-keys/revoke-api-key-dialog.cjs +49 -7
  29. package/dist/cjs/lib/api-keys/revoke-api-key-dialog.cjs.map +1 -1
  30. package/dist/cjs/lib/change-password-dialog.cjs +122 -16
  31. package/dist/cjs/lib/change-password-dialog.cjs.map +1 -1
  32. package/dist/cjs/lib/copy-button.cjs +14 -2
  33. package/dist/cjs/lib/copy-button.cjs.map +1 -1
  34. package/dist/cjs/lib/copy-button.d.cts +2 -1
  35. package/dist/cjs/lib/delete-domain-dialog.cjs +52 -19
  36. package/dist/cjs/lib/delete-domain-dialog.cjs.map +1 -1
  37. package/dist/cjs/lib/delete-user-dialog.cjs +46 -11
  38. package/dist/cjs/lib/delete-user-dialog.cjs.map +1 -1
  39. package/dist/cjs/lib/delete-user-dialog.d.cts +2 -2
  40. package/dist/cjs/lib/domain-actions.cjs +51 -7
  41. package/dist/cjs/lib/domain-actions.cjs.map +1 -1
  42. package/dist/cjs/lib/domain-item.cjs +42 -8
  43. package/dist/cjs/lib/domain-item.cjs.map +1 -1
  44. package/dist/cjs/lib/edit-user-profile-dialog.cjs +62 -11
  45. package/dist/cjs/lib/edit-user-profile-dialog.cjs.map +1 -1
  46. package/dist/cjs/lib/edit-user-role-dialog.cjs +90 -17
  47. package/dist/cjs/lib/edit-user-role-dialog.cjs.map +1 -1
  48. package/dist/cjs/lib/elements.cjs +14 -3
  49. package/dist/cjs/lib/elements.cjs.map +1 -1
  50. package/dist/cjs/lib/elements.d.cts +5 -2
  51. package/dist/cjs/lib/elevated-access.cjs +78 -18
  52. package/dist/cjs/lib/elevated-access.cjs.map +1 -1
  53. package/dist/cjs/lib/generic-error.cjs +53 -11
  54. package/dist/cjs/lib/generic-error.cjs.map +1 -1
  55. package/dist/cjs/lib/generic-error.d.cts +5 -1
  56. package/dist/cjs/lib/i18n/intl-context.cjs +47 -0
  57. package/dist/cjs/lib/i18n/intl-context.cjs.map +1 -0
  58. package/dist/cjs/lib/i18n/intl-context.d.cts +29 -0
  59. package/dist/cjs/lib/i18n/translation.cjs +67 -0
  60. package/dist/cjs/lib/i18n/translation.cjs.map +1 -0
  61. package/dist/cjs/lib/i18n/translation.d.cts +16 -0
  62. package/dist/cjs/lib/i18n/use-locale.cjs +33 -0
  63. package/dist/cjs/lib/i18n/use-locale.cjs.map +1 -0
  64. package/dist/cjs/lib/i18n/use-locale.d.cts +7 -0
  65. package/dist/cjs/lib/i18n/use-translation.cjs +47 -0
  66. package/dist/cjs/lib/i18n/use-translation.cjs.map +1 -0
  67. package/dist/cjs/lib/i18n/use-translation.d.cts +15 -0
  68. package/dist/cjs/lib/identity-providers.d.cts +1 -1
  69. package/dist/cjs/lib/invite-user-dialog.cjs +69 -14
  70. package/dist/cjs/lib/invite-user-dialog.cjs.map +1 -1
  71. package/dist/cjs/lib/logout-all-sessions-dialog.cjs +33 -4
  72. package/dist/cjs/lib/logout-all-sessions-dialog.cjs.map +1 -1
  73. package/dist/cjs/lib/logout-dialog.cjs +34 -10
  74. package/dist/cjs/lib/logout-dialog.cjs.map +1 -1
  75. package/dist/cjs/lib/organization-switcher.cjs +12 -2
  76. package/dist/cjs/lib/organization-switcher.cjs.map +1 -1
  77. package/dist/cjs/lib/pipes.cjs +175 -36
  78. package/dist/cjs/lib/pipes.cjs.map +1 -1
  79. package/dist/cjs/lib/resend-invite-dialog.cjs +67 -17
  80. package/dist/cjs/lib/resend-invite-dialog.cjs.map +1 -1
  81. package/dist/cjs/lib/reset-mfa-dialog.cjs +50 -7
  82. package/dist/cjs/lib/reset-mfa-dialog.cjs.map +1 -1
  83. package/dist/cjs/lib/revoke-invite-dialog.cjs +42 -10
  84. package/dist/cjs/lib/revoke-invite-dialog.cjs.map +1 -1
  85. package/dist/cjs/lib/save-button.cjs +9 -1
  86. package/dist/cjs/lib/save-button.cjs.map +1 -1
  87. package/dist/cjs/lib/set-password-dialog.cjs +101 -13
  88. package/dist/cjs/lib/set-password-dialog.cjs.map +1 -1
  89. package/dist/cjs/lib/user-actions-dropdown.cjs +54 -6
  90. package/dist/cjs/lib/user-actions-dropdown.cjs.map +1 -1
  91. package/dist/cjs/lib/user-profile.cjs +81 -10
  92. package/dist/cjs/lib/user-profile.cjs.map +1 -1
  93. package/dist/cjs/lib/user-security.cjs +127 -25
  94. package/dist/cjs/lib/user-security.cjs.map +1 -1
  95. package/dist/cjs/lib/user-sessions.cjs +74 -15
  96. package/dist/cjs/lib/user-sessions.cjs.map +1 -1
  97. package/dist/cjs/lib/users-management.cjs +265 -49
  98. package/dist/cjs/lib/users-management.cjs.map +1 -1
  99. package/dist/cjs/lib/users-search.cjs +18 -4
  100. package/dist/cjs/lib/users-search.cjs.map +1 -1
  101. package/dist/cjs/lib/utils.cjs +10 -7
  102. package/dist/cjs/lib/utils.cjs.map +1 -1
  103. package/dist/cjs/lib/utils.d.cts +2 -1
  104. package/dist/cjs/lib/view-dns-record-dialog.cjs +89 -18
  105. package/dist/cjs/lib/view-dns-record-dialog.cjs.map +1 -1
  106. package/dist/cjs/workos-widgets.client.cjs +2 -2
  107. package/dist/cjs/workos-widgets.client.cjs.map +1 -1
  108. package/dist/esm/api/endpoint.d.ts +1 -0
  109. package/dist/esm/api/endpoint.js +1 -0
  110. package/dist/esm/api/endpoint.js.map +1 -1
  111. package/dist/esm/index.d.ts +1 -0
  112. package/dist/esm/index.js +3 -1
  113. package/dist/esm/index.js.map +1 -1
  114. package/dist/esm/lib/add-mfa-dialog.js +133 -61
  115. package/dist/esm/lib/add-mfa-dialog.js.map +1 -1
  116. package/dist/esm/lib/admin-portal-domain-verification.js +41 -5
  117. package/dist/esm/lib/admin-portal-domain-verification.js.map +1 -1
  118. package/dist/esm/lib/admin-portal-sso-connection.js +121 -44
  119. package/dist/esm/lib/admin-portal-sso-connection.js.map +1 -1
  120. package/dist/esm/lib/api-keys/api-key-details-card.js +25 -3
  121. package/dist/esm/lib/api-keys/api-key-details-card.js.map +1 -1
  122. package/dist/esm/lib/api-keys/api-key-details-dialog.js +25 -3
  123. package/dist/esm/lib/api-keys/api-key-details-dialog.js.map +1 -1
  124. package/dist/esm/lib/api-keys/api-keys-search.js +13 -4
  125. package/dist/esm/lib/api-keys/api-keys-search.js.map +1 -1
  126. package/dist/esm/lib/api-keys/api-keys-table.js +94 -12
  127. package/dist/esm/lib/api-keys/api-keys-table.js.map +1 -1
  128. package/dist/esm/lib/api-keys/api-keys.js +16 -2
  129. package/dist/esm/lib/api-keys/api-keys.js.map +1 -1
  130. package/dist/esm/lib/api-keys/create-api-key.js +172 -20
  131. package/dist/esm/lib/api-keys/create-api-key.js.map +1 -1
  132. package/dist/esm/lib/api-keys/relative-time.js +12 -2
  133. package/dist/esm/lib/api-keys/relative-time.js.map +1 -1
  134. package/dist/esm/lib/api-keys/revoke-api-key-dialog.js +49 -7
  135. package/dist/esm/lib/api-keys/revoke-api-key-dialog.js.map +1 -1
  136. package/dist/esm/lib/change-password-dialog.js +122 -16
  137. package/dist/esm/lib/change-password-dialog.js.map +1 -1
  138. package/dist/esm/lib/copy-button.d.ts +2 -1
  139. package/dist/esm/lib/copy-button.js +14 -2
  140. package/dist/esm/lib/copy-button.js.map +1 -1
  141. package/dist/esm/lib/delete-domain-dialog.js +52 -19
  142. package/dist/esm/lib/delete-domain-dialog.js.map +1 -1
  143. package/dist/esm/lib/delete-user-dialog.d.ts +2 -2
  144. package/dist/esm/lib/delete-user-dialog.js +36 -11
  145. package/dist/esm/lib/delete-user-dialog.js.map +1 -1
  146. package/dist/esm/lib/domain-actions.js +41 -7
  147. package/dist/esm/lib/domain-actions.js.map +1 -1
  148. package/dist/esm/lib/domain-item.js +42 -8
  149. package/dist/esm/lib/domain-item.js.map +1 -1
  150. package/dist/esm/lib/edit-user-profile-dialog.js +62 -11
  151. package/dist/esm/lib/edit-user-profile-dialog.js.map +1 -1
  152. package/dist/esm/lib/edit-user-role-dialog.js +90 -17
  153. package/dist/esm/lib/edit-user-role-dialog.js.map +1 -1
  154. package/dist/esm/lib/elements.d.ts +5 -2
  155. package/dist/esm/lib/elements.js +14 -3
  156. package/dist/esm/lib/elements.js.map +1 -1
  157. package/dist/esm/lib/elevated-access.js +78 -18
  158. package/dist/esm/lib/elevated-access.js.map +1 -1
  159. package/dist/esm/lib/generic-error.d.ts +5 -1
  160. package/dist/esm/lib/generic-error.js +53 -11
  161. package/dist/esm/lib/generic-error.js.map +1 -1
  162. package/dist/esm/lib/i18n/intl-context.d.ts +29 -0
  163. package/dist/esm/lib/i18n/intl-context.js +12 -0
  164. package/dist/esm/lib/i18n/intl-context.js.map +1 -0
  165. package/dist/esm/lib/i18n/translation.d.ts +16 -0
  166. package/dist/esm/lib/i18n/translation.js +45 -0
  167. package/dist/esm/lib/i18n/translation.js.map +1 -0
  168. package/dist/esm/lib/i18n/use-locale.d.ts +7 -0
  169. package/dist/esm/lib/i18n/use-locale.js +9 -0
  170. package/dist/esm/lib/i18n/use-locale.js.map +1 -0
  171. package/dist/esm/lib/i18n/use-translation.d.ts +15 -0
  172. package/dist/esm/lib/i18n/use-translation.js +23 -0
  173. package/dist/esm/lib/i18n/use-translation.js.map +1 -0
  174. package/dist/esm/lib/identity-providers.d.ts +1 -1
  175. package/dist/esm/lib/invite-user-dialog.js +70 -15
  176. package/dist/esm/lib/invite-user-dialog.js.map +1 -1
  177. package/dist/esm/lib/logout-all-sessions-dialog.js +33 -4
  178. package/dist/esm/lib/logout-all-sessions-dialog.js.map +1 -1
  179. package/dist/esm/lib/logout-dialog.js +34 -10
  180. package/dist/esm/lib/logout-dialog.js.map +1 -1
  181. package/dist/esm/lib/organization-switcher.js +12 -2
  182. package/dist/esm/lib/organization-switcher.js.map +1 -1
  183. package/dist/esm/lib/pipes.js +175 -36
  184. package/dist/esm/lib/pipes.js.map +1 -1
  185. package/dist/esm/lib/resend-invite-dialog.js +67 -17
  186. package/dist/esm/lib/resend-invite-dialog.js.map +1 -1
  187. package/dist/esm/lib/reset-mfa-dialog.js +50 -7
  188. package/dist/esm/lib/reset-mfa-dialog.js.map +1 -1
  189. package/dist/esm/lib/revoke-invite-dialog.js +42 -10
  190. package/dist/esm/lib/revoke-invite-dialog.js.map +1 -1
  191. package/dist/esm/lib/save-button.js +9 -1
  192. package/dist/esm/lib/save-button.js.map +1 -1
  193. package/dist/esm/lib/set-password-dialog.js +101 -13
  194. package/dist/esm/lib/set-password-dialog.js.map +1 -1
  195. package/dist/esm/lib/user-actions-dropdown.js +54 -6
  196. package/dist/esm/lib/user-actions-dropdown.js.map +1 -1
  197. package/dist/esm/lib/user-profile.js +81 -10
  198. package/dist/esm/lib/user-profile.js.map +1 -1
  199. package/dist/esm/lib/user-security.js +127 -25
  200. package/dist/esm/lib/user-security.js.map +1 -1
  201. package/dist/esm/lib/user-sessions.js +74 -15
  202. package/dist/esm/lib/user-sessions.js.map +1 -1
  203. package/dist/esm/lib/users-management.js +266 -51
  204. package/dist/esm/lib/users-management.js.map +1 -1
  205. package/dist/esm/lib/users-search.js +18 -4
  206. package/dist/esm/lib/users-search.js.map +1 -1
  207. package/dist/esm/lib/utils.d.ts +2 -1
  208. package/dist/esm/lib/utils.js +10 -7
  209. package/dist/esm/lib/utils.js.map +1 -1
  210. package/dist/esm/lib/view-dns-record-dialog.js +89 -18
  211. package/dist/esm/lib/view-dns-record-dialog.js.map +1 -1
  212. package/dist/esm/workos-widgets.client.js +2 -2
  213. package/dist/esm/workos-widgets.client.js.map +1 -1
  214. package/package.json +11 -2
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { Callout, Flex, Text, VisuallyHidden } from "@radix-ui/themes";
4
4
  import * as React from "react";
5
5
  import { Dialog, Button, Select, TextField } from "./elements.js";
@@ -7,8 +7,11 @@ import { Label } from "./elements.js";
7
7
  import { isErrorLike } from "./utils.js";
8
8
  import { useInviteUser } from "./api/user.js";
9
9
  import { useRoles } from "../api/endpoint.js";
10
+ import { Translation } from "./i18n/translation.js";
11
+ import { useTranslation } from "./i18n/use-translation.js";
10
12
  const PLACEHOLDER_ROLE = "_rolePlaceholder";
11
13
  function InviteUserDialog({ children }) {
14
+ const translate = useTranslation();
12
15
  const [open, setOpen] = React.useState(false);
13
16
  const dialogId = toId("invite-user", React.useId());
14
17
  const formId = toId(dialogId, "form");
@@ -46,8 +49,22 @@ function InviteUserDialog({ children }) {
46
49
  return /* @__PURE__ */ jsxs(Dialog.Root, { open, onOpenChange: setOpen, children: [
47
50
  children && /* @__PURE__ */ jsx(Dialog.Trigger, { children }),
48
51
  /* @__PURE__ */ jsxs(Dialog.Content, { maxWidth: "480px", children: [
49
- /* @__PURE__ */ jsx(Dialog.Title, { children: "Invite user" }),
50
- /* @__PURE__ */ jsx(Dialog.Description, { children: "An invitation will be sent to this email address with a link to complete their account." }),
52
+ /* @__PURE__ */ jsx(Dialog.Title, { children: /* @__PURE__ */ jsx(
53
+ Translation,
54
+ {
55
+ defaultMessage: "Invite user",
56
+ id: "6+aYFi",
57
+ description: "Dialog title for inviting a user"
58
+ }
59
+ ) }),
60
+ /* @__PURE__ */ jsx(Dialog.Description, { children: /* @__PURE__ */ jsx(
61
+ Translation,
62
+ {
63
+ defaultMessage: "An invitation will be sent to this email address with a link to complete their account.",
64
+ id: "IicELr",
65
+ description: "Dialog description explaining invitation process"
66
+ }
67
+ ) }),
51
68
  /* @__PURE__ */ jsx(Flex, { direction: "column", gap: "4", mt: "5", asChild: true, children: /* @__PURE__ */ jsxs(
52
69
  "form",
53
70
  {
@@ -65,7 +82,11 @@ function InviteUserDialog({ children }) {
65
82
  {
66
83
  rootId: dialogId,
67
84
  name: "email",
68
- label: "Email address",
85
+ label: translate({
86
+ defaultMessage: "Email address",
87
+ id: "ACNqhk",
88
+ description: "Label for email address field"
89
+ }),
69
90
  error: formErrors.fields.email,
70
91
  required: true,
71
92
  control: (props) => /* @__PURE__ */ jsx(
@@ -76,7 +97,11 @@ function InviteUserDialog({ children }) {
76
97
  "data-lpignore": "true",
77
98
  type: "email",
78
99
  autoComplete: "off",
79
- placeholder: "Enter an email address"
100
+ placeholder: translate({
101
+ defaultMessage: "Enter an email address",
102
+ id: "0ulARV",
103
+ description: "Placeholder for email address field"
104
+ })
80
105
  }
81
106
  )
82
107
  }
@@ -86,15 +111,24 @@ function InviteUserDialog({ children }) {
86
111
  {
87
112
  rootId: dialogId,
88
113
  name: "role",
89
- label: "Role",
114
+ label: translate({
115
+ defaultMessage: "Role",
116
+ id: "1Htc3a",
117
+ description: "Label for role selection field"
118
+ }),
90
119
  error: formErrors.fields.role,
91
120
  disabled: rolesQuery.isPending || roles.length <= 1,
92
- info: roles.length === 1 ? /* @__PURE__ */ jsxs(Fragment, { children: [
93
- "New users will be invited with the",
94
- " ",
95
- /* @__PURE__ */ jsx(Text, { weight: "bold", children: roles[0].name }),
96
- " role, as it is the only one available."
97
- ] }) : void 0,
121
+ info: roles.length === 1 ? /* @__PURE__ */ jsx(
122
+ Translation,
123
+ {
124
+ defaultMessage: "New users will be invited with the {roleName} role, as it is the only one available.",
125
+ id: "/CNKkm",
126
+ description: "Info message when only one role is available",
127
+ values: {
128
+ roleName: /* @__PURE__ */ jsx(Text, { weight: "bold", children: roles[0].name })
129
+ }
130
+ }
131
+ ) : void 0,
98
132
  control: ({
99
133
  id,
100
134
  "aria-invalid": ariaInvalid,
@@ -116,7 +150,14 @@ function InviteUserDialog({ children }) {
116
150
  }
117
151
  ),
118
152
  /* @__PURE__ */ jsxs(Select.Content, { children: [
119
- /* @__PURE__ */ jsx(Select.Item, { value: PLACEHOLDER_ROLE, disabled: true, children: "Select a role" }),
153
+ /* @__PURE__ */ jsx(Select.Item, { value: PLACEHOLDER_ROLE, disabled: true, children: /* @__PURE__ */ jsx(
154
+ Translation,
155
+ {
156
+ defaultMessage: "Select a role",
157
+ id: "0VMIWs",
158
+ description: "Placeholder option for role selection"
159
+ }
160
+ ) }),
120
161
  roles.map((role) => /* @__PURE__ */ jsx(Select.Item, { value: role.slug, children: role.name }, role.slug))
121
162
  ] })
122
163
  ]
@@ -129,7 +170,14 @@ function InviteUserDialog({ children }) {
129
170
  ) }),
130
171
  formErrors.form ? /* @__PURE__ */ jsx(Callout.Root, { color: "red", mt: "4", mb: "-2", children: /* @__PURE__ */ jsx(Callout.Text, { children: formErrors.form }) }) : null,
131
172
  /* @__PURE__ */ jsxs(Flex, { mt: "5", gap: "3", justify: "end", children: [
132
- /* @__PURE__ */ jsx(Dialog.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "secondary", disabled: inviteUser.isPending, children: "Cancel" }) }),
173
+ /* @__PURE__ */ jsx(Dialog.Close, { children: /* @__PURE__ */ jsx(Button, { variant: "secondary", disabled: inviteUser.isPending, children: /* @__PURE__ */ jsx(
174
+ Translation,
175
+ {
176
+ defaultMessage: "Cancel",
177
+ id: "hHNj31",
178
+ description: "Cancel button text"
179
+ }
180
+ ) }) }),
133
181
  /* @__PURE__ */ jsx(
134
182
  Button,
135
183
  {
@@ -137,7 +185,14 @@ function InviteUserDialog({ children }) {
137
185
  form: formId,
138
186
  loading: inviteUser.isPending,
139
187
  disabled: rolesQuery.isPending || void 0,
140
- children: "Invite"
188
+ children: /* @__PURE__ */ jsx(
189
+ Translation,
190
+ {
191
+ defaultMessage: "Invite",
192
+ id: "JIQROV",
193
+ description: "Invite button text to send invitation"
194
+ }
195
+ )
141
196
  }
142
197
  )
143
198
  ] }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/invite-user-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Callout, Flex, Text, VisuallyHidden } from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport { Dialog, Button, Select, TextField } from \"./elements.js\";\nimport { Label } from \"./elements.js\";\nimport { isErrorLike } from \"./utils.js\";\nimport { useInviteUser } from \"./api/user.js\";\nimport { InviteMemberInput, MemberRole, useRoles } from \"../api/endpoint.js\";\n\n/**\n * Used to stub a fake value for the role select. It will be selected by default\n * before the role query resolves, or if the query results in an error. We do\n * this because we need to provide _any_ value to the select to avoid\n * controlled/uncontrolled bugs.\n */\nconst PLACEHOLDER_ROLE = \"_rolePlaceholder\";\n\ninterface InviteUserDialogProps {\n children?: React.ReactNode;\n}\n\nexport function InviteUserDialog({ children }: InviteUserDialogProps) {\n const [open, setOpen] = React.useState(false);\n const dialogId = toId(\"invite-user\", React.useId());\n const formId = toId(dialogId, \"form\");\n\n const inviteUser = useInviteUser();\n const rolesQuery = useRoles({\n query: { initialData: [] },\n });\n const roles = rolesQuery.data;\n const [selectedRole, setSelectedRole] = React.useState(\n () => getDefaultRole(roles)?.slug || PLACEHOLDER_ROLE,\n );\n React.useEffect(() => {\n // Update the selected role if it's not in the list (eg if the list was\n // previously empty and the query resolved)\n setSelectedRole((selectedRole) => {\n if (roles.find((role) => role.slug === selectedRole)) {\n // if current selected role is in the new list, don't change it\n return selectedRole;\n }\n return getDefaultRole(roles)?.slug || PLACEHOLDER_ROLE;\n });\n }, [roles]);\n\n const onSubmitForm = (data: InviteMemberInput) => {\n if (inviteUser.isPending || rolesQuery.status !== \"success\") {\n return;\n }\n inviteUser.mutate(\n { data },\n {\n onSuccess: () => {\n setOpen(false);\n },\n },\n );\n };\n\n const formErrors = getFormErrors(inviteUser.error);\n useFormFieldFocusOnError(dialogId, inviteUser.error);\n\n return (\n <Dialog.Root open={open} onOpenChange={setOpen}>\n {children && <Dialog.Trigger>{children}</Dialog.Trigger>}\n <Dialog.Content maxWidth=\"480px\" key={String(open)}>\n <Dialog.Title>Invite user</Dialog.Title>\n <Dialog.Description>\n An invitation will be sent to this email address with a link to\n complete their account.\n </Dialog.Description>\n <Flex direction=\"column\" gap=\"4\" mt=\"5\" asChild>\n <form\n id={formId}\n onSubmit={async (event) => {\n event.preventDefault();\n onSubmitForm({\n email: event.currentTarget.email.value,\n roles: [selectedRole],\n });\n }}\n >\n <FormField\n rootId={dialogId}\n name=\"email\"\n label=\"Email address\"\n error={formErrors.fields.email}\n required\n control={(props) => (\n <TextField\n {...props}\n data-1p-ignore=\"true\"\n data-lpignore=\"true\"\n type=\"email\"\n autoComplete=\"off\"\n placeholder=\"Enter an email address\"\n />\n )}\n />\n\n <FormField\n rootId={dialogId}\n name=\"role\"\n label=\"Role\"\n error={formErrors.fields.role}\n disabled={rolesQuery.isPending || roles.length <= 1}\n info={\n roles.length === 1 ? (\n <>\n New users will be invited with the{\" \"}\n <Text weight=\"bold\">{roles[0].name}</Text> role, as it is\n the only one available.\n </>\n ) : undefined\n }\n control={({\n id,\n \"aria-invalid\": ariaInvalid,\n \"aria-describedby\": ariaDescribedBy,\n ...props\n }) => (\n <Select.Root\n {...props}\n value={selectedRole}\n onValueChange={setSelectedRole}\n >\n <Select.Trigger\n id={id}\n aria-invalid={ariaInvalid}\n aria-describedby={ariaDescribedBy}\n />\n <Select.Content>\n <Select.Item value={PLACEHOLDER_ROLE} disabled>\n Select a role\n </Select.Item>\n {roles.map((role) => (\n <Select.Item key={role.slug} value={role.slug}>\n {role.name}\n </Select.Item>\n ))}\n </Select.Content>\n </Select.Root>\n )}\n />\n </form>\n </Flex>\n\n {formErrors.form ? (\n <Callout.Root color=\"red\" mt=\"4\" mb=\"-2\">\n <Callout.Text>{formErrors.form}</Callout.Text>\n </Callout.Root>\n ) : null}\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <Button variant=\"secondary\" disabled={inviteUser.isPending}>\n Cancel\n </Button>\n </Dialog.Close>\n <Button\n type=\"submit\"\n form={formId}\n loading={inviteUser.isPending}\n disabled={rolesQuery.isPending || undefined}\n >\n Invite\n </Button>\n </Flex>\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">{formErrors.form}</section>\n </VisuallyHidden>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\ninterface FormControlRenderProps {\n id: string;\n name: string;\n \"aria-describedby\": string | undefined;\n \"aria-invalid\"?: boolean;\n required: boolean | undefined;\n disabled: boolean | undefined;\n}\n\nfunction FormField({\n rootId,\n name,\n label,\n error,\n info,\n control,\n required,\n disabled,\n}: {\n rootId: string;\n name: string;\n label: string;\n error?: React.ReactNode;\n info?: React.ReactNode;\n control: (props: FormControlRenderProps) => React.ReactNode;\n required?: boolean;\n disabled?: boolean;\n}) {\n const fieldId = toId(rootId, name);\n const errorId = toId(rootId, name, \"error\");\n const infoId = toId(rootId, name, \"info\");\n return (\n <Flex direction=\"column\" gap=\"1\">\n <Label htmlFor={fieldId}>{label}</Label>\n {control({\n id: fieldId,\n name,\n \"aria-describedby\": (() => {\n const tags: string[] = [];\n if (error) {\n tags.push(errorId);\n }\n if (info) {\n tags.push(infoId);\n }\n if (tags.length === 0) {\n return undefined;\n }\n return tags.join(\" \");\n })(),\n \"aria-invalid\": !!error || undefined,\n required: required || undefined,\n disabled: disabled || undefined,\n })}\n\n {error ? (\n <Text color=\"red\" size=\"2\" id={errorId}>\n {error}\n </Text>\n ) : null}\n {info ? (\n <Text color=\"gray\" size=\"2\" id={infoId} mt=\"1\">\n {info}\n </Text>\n ) : null}\n </Flex>\n );\n}\n\nfunction toId(...parts: string[]) {\n return parts.join(\"-\");\n}\n\nfunction getFormErrors(queryError: unknown) {\n const formErrors = {\n form: null as string | null,\n fields: {\n email: null as string | null,\n role: null as string | null,\n },\n };\n\n if (queryError) {\n if (!isErrorLike(queryError)) {\n return {\n ...formErrors,\n form: \"An unexpected error occurred. Please try again.\",\n };\n }\n\n switch (queryError.message.toLowerCase()) {\n case \"user already exists\":\n case \"user already invited\":\n case \"invalid email\":\n formErrors.fields.email = queryError.message;\n break;\n case \"invalid role\":\n formErrors.fields.role = queryError.message;\n break;\n default:\n // TODO handle more cases for various server errors\n formErrors.form =\n \"There was an error inviting this user. Please refresh the page and try again.\";\n break;\n }\n }\n\n return formErrors;\n}\n\nfunction useFormFieldFocusOnError(dialogId: string, queryError: unknown) {\n React.useEffect(() => {\n const fieldErrors = getFormErrors(queryError).fields;\n for (const [name, error] of Object.entries(fieldErrors)) {\n if (error) {\n const fieldElement = document.getElementById(toId(dialogId, name)) as\n | HTMLInputElement\n | HTMLButtonElement\n | null;\n if (fieldElement) {\n fieldElement?.focus();\n if (\"select\" in fieldElement) {\n fieldElement.select();\n }\n }\n break;\n }\n }\n }, [dialogId, queryError]);\n}\n\nfunction getDefaultRole(roles: MemberRole[]) {\n return roles.find((role) => role.default) || roles[0];\n}\n"],"mappings":"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","names":["selectedRole"]}
1
+ {"version":3,"sources":["../../../src/lib/invite-user-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { Callout, Flex, Text, VisuallyHidden } from \"@radix-ui/themes\";\nimport * as React from \"react\";\nimport { Dialog, Button, Select, TextField } from \"./elements.js\";\nimport { Label } from \"./elements.js\";\nimport { isErrorLike } from \"./utils.js\";\nimport { useInviteUser } from \"./api/user.js\";\nimport { InviteMemberInput, MemberRole, useRoles } from \"../api/endpoint.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\n\n/**\n * Used to stub a fake value for the role select. It will be selected by default\n * before the role query resolves, or if the query results in an error. We do\n * this because we need to provide _any_ value to the select to avoid\n * controlled/uncontrolled bugs.\n */\nconst PLACEHOLDER_ROLE = \"_rolePlaceholder\";\n\ninterface InviteUserDialogProps {\n children?: React.ReactNode;\n}\n\nexport function InviteUserDialog({ children }: InviteUserDialogProps) {\n const translate = useTranslation();\n const [open, setOpen] = React.useState(false);\n const dialogId = toId(\"invite-user\", React.useId());\n const formId = toId(dialogId, \"form\");\n\n const inviteUser = useInviteUser();\n const rolesQuery = useRoles({\n query: { initialData: [] },\n });\n const roles = rolesQuery.data;\n const [selectedRole, setSelectedRole] = React.useState(\n () => getDefaultRole(roles)?.slug || PLACEHOLDER_ROLE,\n );\n React.useEffect(() => {\n // Update the selected role if it's not in the list (eg if the list was\n // previously empty and the query resolved)\n setSelectedRole((selectedRole) => {\n if (roles.find((role) => role.slug === selectedRole)) {\n // if current selected role is in the new list, don't change it\n return selectedRole;\n }\n return getDefaultRole(roles)?.slug || PLACEHOLDER_ROLE;\n });\n }, [roles]);\n\n const onSubmitForm = (data: InviteMemberInput) => {\n if (inviteUser.isPending || rolesQuery.status !== \"success\") {\n return;\n }\n inviteUser.mutate(\n { data },\n {\n onSuccess: () => {\n setOpen(false);\n },\n },\n );\n };\n\n const formErrors = getFormErrors(inviteUser.error);\n useFormFieldFocusOnError(dialogId, inviteUser.error);\n\n return (\n <Dialog.Root open={open} onOpenChange={setOpen}>\n {children && <Dialog.Trigger>{children}</Dialog.Trigger>}\n <Dialog.Content maxWidth=\"480px\" key={String(open)}>\n <Dialog.Title>\n <Translation\n defaultMessage=\"Invite user\"\n id=\"6+aYFi\"\n description=\"Dialog title for inviting a user\"\n />\n </Dialog.Title>\n <Dialog.Description>\n <Translation\n defaultMessage=\"An invitation will be sent to this email address with a link to complete their account.\"\n id=\"IicELr\"\n description=\"Dialog description explaining invitation process\"\n />\n </Dialog.Description>\n <Flex direction=\"column\" gap=\"4\" mt=\"5\" asChild>\n <form\n id={formId}\n onSubmit={async (event) => {\n event.preventDefault();\n onSubmitForm({\n email: event.currentTarget.email.value,\n roles: [selectedRole],\n });\n }}\n >\n <FormField\n rootId={dialogId}\n name=\"email\"\n label={translate({\n defaultMessage: \"Email address\",\n id: \"ACNqhk\",\n description: \"Label for email address field\",\n })}\n error={formErrors.fields.email}\n required\n control={(props) => (\n <TextField\n {...props}\n data-1p-ignore=\"true\"\n data-lpignore=\"true\"\n type=\"email\"\n autoComplete=\"off\"\n placeholder={translate({\n defaultMessage: \"Enter an email address\",\n id: \"0ulARV\",\n description: \"Placeholder for email address field\",\n })}\n />\n )}\n />\n\n <FormField\n rootId={dialogId}\n name=\"role\"\n label={translate({\n defaultMessage: \"Role\",\n id: \"1Htc3a\",\n description: \"Label for role selection field\",\n })}\n error={formErrors.fields.role}\n disabled={rolesQuery.isPending || roles.length <= 1}\n info={\n roles.length === 1 ? (\n <Translation\n defaultMessage=\"New users will be invited with the {roleName} role, as it is the only one available.\"\n id=\"/CNKkm\"\n description=\"Info message when only one role is available\"\n values={{\n roleName: <Text weight=\"bold\">{roles[0].name}</Text>,\n }}\n />\n ) : undefined\n }\n control={({\n id,\n \"aria-invalid\": ariaInvalid,\n \"aria-describedby\": ariaDescribedBy,\n ...props\n }) => (\n <Select.Root\n {...props}\n value={selectedRole}\n onValueChange={setSelectedRole}\n >\n <Select.Trigger\n id={id}\n aria-invalid={ariaInvalid}\n aria-describedby={ariaDescribedBy}\n />\n <Select.Content>\n <Select.Item value={PLACEHOLDER_ROLE} disabled>\n <Translation\n defaultMessage=\"Select a role\"\n id=\"0VMIWs\"\n description=\"Placeholder option for role selection\"\n />\n </Select.Item>\n {roles.map((role) => (\n <Select.Item key={role.slug} value={role.slug}>\n {role.name}\n </Select.Item>\n ))}\n </Select.Content>\n </Select.Root>\n )}\n />\n </form>\n </Flex>\n\n {formErrors.form ? (\n <Callout.Root color=\"red\" mt=\"4\" mb=\"-2\">\n <Callout.Text>{formErrors.form}</Callout.Text>\n </Callout.Root>\n ) : null}\n\n <Flex mt=\"5\" gap=\"3\" justify=\"end\">\n <Dialog.Close>\n <Button variant=\"secondary\" disabled={inviteUser.isPending}>\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n <Button\n type=\"submit\"\n form={formId}\n loading={inviteUser.isPending}\n disabled={rolesQuery.isPending || undefined}\n >\n <Translation\n defaultMessage=\"Invite\"\n id=\"JIQROV\"\n description=\"Invite button text to send invitation\"\n />\n </Button>\n </Flex>\n {/* mirror errors in a live region */}\n <VisuallyHidden asChild>\n <section aria-live=\"polite\">{formErrors.form}</section>\n </VisuallyHidden>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\ninterface FormControlRenderProps {\n id: string;\n name: string;\n \"aria-describedby\": string | undefined;\n \"aria-invalid\"?: boolean;\n required: boolean | undefined;\n disabled: boolean | undefined;\n}\n\nfunction FormField({\n rootId,\n name,\n label,\n error,\n info,\n control,\n required,\n disabled,\n}: {\n rootId: string;\n name: string;\n label: string;\n error?: React.ReactNode;\n info?: React.ReactNode;\n control: (props: FormControlRenderProps) => React.ReactNode;\n required?: boolean;\n disabled?: boolean;\n}) {\n const fieldId = toId(rootId, name);\n const errorId = toId(rootId, name, \"error\");\n const infoId = toId(rootId, name, \"info\");\n return (\n <Flex direction=\"column\" gap=\"1\">\n <Label htmlFor={fieldId}>{label}</Label>\n {control({\n id: fieldId,\n name,\n \"aria-describedby\": (() => {\n const tags: string[] = [];\n if (error) {\n tags.push(errorId);\n }\n if (info) {\n tags.push(infoId);\n }\n if (tags.length === 0) {\n return undefined;\n }\n return tags.join(\" \");\n })(),\n \"aria-invalid\": !!error || undefined,\n required: required || undefined,\n disabled: disabled || undefined,\n })}\n\n {error ? (\n <Text color=\"red\" size=\"2\" id={errorId}>\n {error}\n </Text>\n ) : null}\n {info ? (\n <Text color=\"gray\" size=\"2\" id={infoId} mt=\"1\">\n {info}\n </Text>\n ) : null}\n </Flex>\n );\n}\n\nfunction toId(...parts: string[]) {\n return parts.join(\"-\");\n}\n\nfunction getFormErrors(queryError: unknown) {\n const formErrors = {\n form: null as string | null,\n fields: {\n email: null as string | null,\n role: null as string | null,\n },\n };\n\n if (queryError) {\n if (!isErrorLike(queryError)) {\n return {\n ...formErrors,\n form: \"An unexpected error occurred. Please try again.\",\n };\n }\n\n switch (queryError.message.toLowerCase()) {\n case \"user already exists\":\n case \"user already invited\":\n case \"invalid email\":\n formErrors.fields.email = queryError.message;\n break;\n case \"invalid role\":\n formErrors.fields.role = queryError.message;\n break;\n default:\n // TODO handle more cases for various server errors\n formErrors.form =\n \"There was an error inviting this user. Please refresh the page and try again.\";\n break;\n }\n }\n\n return formErrors;\n}\n\n// Note: Error messages in getFormErrors are kept as plain strings\n// since they are displayed dynamically\n\nfunction useFormFieldFocusOnError(dialogId: string, queryError: unknown) {\n React.useEffect(() => {\n const fieldErrors = getFormErrors(queryError).fields;\n for (const [name, error] of Object.entries(fieldErrors)) {\n if (error) {\n const fieldElement = document.getElementById(toId(dialogId, name)) as\n | HTMLInputElement\n | HTMLButtonElement\n | null;\n if (fieldElement) {\n fieldElement?.focus();\n if (\"select\" in fieldElement) {\n fieldElement.select();\n }\n }\n break;\n }\n }\n }, [dialogId, queryError]);\n}\n\nfunction getDefaultRole(roles: MemberRole[]) {\n return roles.find((role) => role.default) || roles[0];\n}\n"],"mappings":"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","names":["selectedRole"]}
@@ -6,6 +6,7 @@ import { AlertDialog, Button } from "./elements.js";
6
6
  import { getSessionsQueryKey, useRevokeAllSessions } from "../api/endpoint.js";
7
7
  import { useQueryClient } from "@tanstack/react-query";
8
8
  import { SaveButton } from "./save-button.js";
9
+ import { Translation } from "./i18n/translation.js";
9
10
  function LogoutAllSessionsDialog({
10
11
  open,
11
12
  onOpenChange,
@@ -25,8 +26,22 @@ function LogoutAllSessionsDialog({
25
26
  });
26
27
  }, [client, onOpenChange]);
27
28
  return /* @__PURE__ */ jsx(AlertDialog.Root, { open, onOpenChange, ...props, children: /* @__PURE__ */ jsxs(AlertDialog.Content, { maxWidth: "480px", children: [
28
- /* @__PURE__ */ jsx(AlertDialog.Title, { children: "Sign out of all other devices?" }),
29
- /* @__PURE__ */ jsx(AlertDialog.Description, { children: "You will be logged out of all other active sessions on other devices, except this one." }),
29
+ /* @__PURE__ */ jsx(AlertDialog.Title, { children: /* @__PURE__ */ jsx(
30
+ Translation,
31
+ {
32
+ defaultMessage: "Sign out of all other devices?",
33
+ id: "x//BWg",
34
+ description: "Dialog title asking to confirm signing out of all other devices"
35
+ }
36
+ ) }),
37
+ /* @__PURE__ */ jsx(AlertDialog.Description, { children: /* @__PURE__ */ jsx(
38
+ Translation,
39
+ {
40
+ defaultMessage: "You will be logged out of all other active sessions on other devices, except this one.",
41
+ id: "GftsX9",
42
+ description: "Description explaining all other sessions will be logged out"
43
+ }
44
+ ) }),
30
45
  /* @__PURE__ */ jsx(Flex, { gap: "3", justify: "end", mt: "5", asChild: true, children: /* @__PURE__ */ jsxs(
31
46
  "form",
32
47
  {
@@ -40,7 +55,14 @@ function LogoutAllSessionsDialog({
40
55
  {
41
56
  variant: "secondary",
42
57
  disabled: revokeAllSessions.isPending || revokeAllSessions.isSuccess,
43
- children: "Cancel"
58
+ children: /* @__PURE__ */ jsx(
59
+ Translation,
60
+ {
61
+ defaultMessage: "Cancel",
62
+ id: "Pnmy4H",
63
+ description: "Button to cancel signing out of all devices"
64
+ }
65
+ )
44
66
  }
45
67
  ) }),
46
68
  /* @__PURE__ */ jsx(
@@ -50,7 +72,14 @@ function LogoutAllSessionsDialog({
50
72
  loading: revokeAllSessions.isPending,
51
73
  done: revokeAllSessions.isSuccess,
52
74
  onDone: handleDone,
53
- children: /* @__PURE__ */ jsx(Button, { variant: "destructive", type: "submit", children: "Sign out" })
75
+ children: /* @__PURE__ */ jsx(Button, { variant: "destructive", type: "submit", children: /* @__PURE__ */ jsx(
76
+ Translation,
77
+ {
78
+ defaultMessage: "Sign out",
79
+ id: "1Fb48o",
80
+ description: "Button to confirm signing out of all other devices"
81
+ }
82
+ ) })
54
83
  }
55
84
  )
56
85
  ]
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/logout-all-sessions-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Flex } from \"@radix-ui/themes\";\nimport { type ReactNode } from \"react\";\nimport { AlertDialog, Button } from \"./elements.js\";\nimport { getSessionsQueryKey, useRevokeAllSessions } from \"../api/endpoint.js\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { SaveButton } from \"./save-button.js\";\n\ninterface LogoutAllSessionsDialogProps extends AlertDialog.RootProps {\n children?: ReactNode;\n currentSessionId: string;\n}\n\nexport function LogoutAllSessionsDialog({\n open,\n onOpenChange,\n children,\n currentSessionId,\n ...props\n}: LogoutAllSessionsDialogProps) {\n const client = useQueryClient();\n\n const revokeAllSessions = useRevokeAllSessions();\n\n const onSubmitForm = () => {\n revokeAllSessions.mutate({ data: { currentSessionId } });\n };\n\n const handleDone = React.useCallback(() => {\n onOpenChange?.(false);\n\n client.invalidateQueries({\n queryKey: getSessionsQueryKey(),\n });\n }, [client, onOpenChange]);\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>\n <AlertDialog.Content maxWidth=\"480px\">\n <AlertDialog.Title>Sign out of all other devices?</AlertDialog.Title>\n <AlertDialog.Description>\n You will be logged out of all other active sessions on other devices,\n except this one.\n </AlertDialog.Description>\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n disabled={\n revokeAllSessions.isPending || revokeAllSessions.isSuccess\n }\n >\n Cancel\n </Button>\n </AlertDialog.Cancel>\n\n <SaveButton\n asChild\n loading={revokeAllSessions.isPending}\n done={revokeAllSessions.isSuccess}\n onDone={handleDone}\n >\n <Button variant=\"destructive\" type=\"submit\">\n Sign out\n </Button>\n </SaveButton>\n </form>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n}\n"],"mappings":";AAyCQ,cAOE,YAPF;AAvCR,YAAY,WAAW;AACvB,SAAS,YAAY;AAErB,SAAS,aAAa,cAAc;AACpC,SAAS,qBAAqB,4BAA4B;AAC1D,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAOpB,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAiC;AAC/B,QAAM,SAAS,eAAe;AAE9B,QAAM,oBAAoB,qBAAqB;AAE/C,QAAM,eAAe,MAAM;AACzB,sBAAkB,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;AAAA,EACzD;AAEA,QAAM,aAAa,MAAM,YAAY,MAAM;AACzC,mBAAe,KAAK;AAEpB,WAAO,kBAAkB;AAAA,MACvB,UAAU,oBAAoB;AAAA,IAChC,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,YAAY,CAAC;AAEzB,SACE,oBAAC,YAAY,MAAZ,EAAiB,MAAY,cAA6B,GAAG,OAC5D,+BAAC,YAAY,SAAZ,EAAoB,UAAS,SAC5B;AAAA,wBAAC,YAAY,OAAZ,EAAkB,4CAA8B;AAAA,IACjD,oBAAC,YAAY,aAAZ,EAAwB,oGAGzB;AAAA,IAEA,oBAAC,QAAK,KAAI,KAAI,SAAQ,OAAM,IAAG,KAAI,SAAO,MACxC;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,CAAC,UAAU;AACnB,gBAAM,eAAe;AACrB,uBAAa;AAAA,QACf;AAAA,QAEA;AAAA,8BAAC,YAAY,QAAZ,EACC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,UACE,kBAAkB,aAAa,kBAAkB;AAAA,cAEpD;AAAA;AAAA,UAED,GACF;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAO;AAAA,cACP,SAAS,kBAAkB;AAAA,cAC3B,MAAM,kBAAkB;AAAA,cACxB,QAAQ;AAAA,cAER,8BAAC,UAAO,SAAQ,eAAc,MAAK,UAAS,sBAE5C;AAAA;AAAA,UACF;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/logout-all-sessions-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Flex } from \"@radix-ui/themes\";\nimport { type ReactNode } from \"react\";\nimport { AlertDialog, Button } from \"./elements.js\";\nimport { getSessionsQueryKey, useRevokeAllSessions } from \"../api/endpoint.js\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { SaveButton } from \"./save-button.js\";\nimport { Translation } from \"./i18n/translation.js\";\n\ninterface LogoutAllSessionsDialogProps extends AlertDialog.RootProps {\n children?: ReactNode;\n currentSessionId: string;\n}\n\nexport function LogoutAllSessionsDialog({\n open,\n onOpenChange,\n children,\n currentSessionId,\n ...props\n}: LogoutAllSessionsDialogProps) {\n const client = useQueryClient();\n\n const revokeAllSessions = useRevokeAllSessions();\n\n const onSubmitForm = () => {\n revokeAllSessions.mutate({ data: { currentSessionId } });\n };\n\n const handleDone = React.useCallback(() => {\n onOpenChange?.(false);\n\n client.invalidateQueries({\n queryKey: getSessionsQueryKey(),\n });\n }, [client, onOpenChange]);\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>\n <AlertDialog.Content maxWidth=\"480px\">\n <AlertDialog.Title>\n <Translation\n defaultMessage=\"Sign out of all other devices?\"\n id=\"x//BWg\"\n description=\"Dialog title asking to confirm signing out of all other devices\"\n />\n </AlertDialog.Title>\n <AlertDialog.Description>\n <Translation\n defaultMessage=\"You will be logged out of all other active sessions on other devices, except this one.\"\n id=\"GftsX9\"\n description=\"Description explaining all other sessions will be logged out\"\n />\n </AlertDialog.Description>\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n disabled={\n revokeAllSessions.isPending || revokeAllSessions.isSuccess\n }\n >\n <Translation\n defaultMessage=\"Cancel\"\n id=\"Pnmy4H\"\n description=\"Button to cancel signing out of all devices\"\n />\n </Button>\n </AlertDialog.Cancel>\n\n <SaveButton\n asChild\n loading={revokeAllSessions.isPending}\n done={revokeAllSessions.isSuccess}\n onDone={handleDone}\n >\n <Button variant=\"destructive\" type=\"submit\">\n <Translation\n defaultMessage=\"Sign out\"\n id=\"1Fb48o\"\n description=\"Button to confirm signing out of all other devices\"\n />\n </Button>\n </SaveButton>\n </form>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n}\n"],"mappings":";AA2CU,cAeA,YAfA;AAzCV,YAAY,WAAW;AACvB,SAAS,YAAY;AAErB,SAAS,aAAa,cAAc;AACpC,SAAS,qBAAqB,4BAA4B;AAC1D,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAC3B,SAAS,mBAAmB;AAOrB,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAiC;AAC/B,QAAM,SAAS,eAAe;AAE9B,QAAM,oBAAoB,qBAAqB;AAE/C,QAAM,eAAe,MAAM;AACzB,sBAAkB,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC;AAAA,EACzD;AAEA,QAAM,aAAa,MAAM,YAAY,MAAM;AACzC,mBAAe,KAAK;AAEpB,WAAO,kBAAkB;AAAA,MACvB,UAAU,oBAAoB;AAAA,IAChC,CAAC;AAAA,EACH,GAAG,CAAC,QAAQ,YAAY,CAAC;AAEzB,SACE,oBAAC,YAAY,MAAZ,EAAiB,MAAY,cAA6B,GAAG,OAC5D,+BAAC,YAAY,SAAZ,EAAoB,UAAS,SAC5B;AAAA,wBAAC,YAAY,OAAZ,EACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,IACA,oBAAC,YAAY,aAAZ,EACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,IAEA,oBAAC,QAAK,KAAI,KAAI,SAAQ,OAAM,IAAG,KAAI,SAAO,MACxC;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,CAAC,UAAU;AACnB,gBAAM,eAAe;AACrB,uBAAa;AAAA,QACf;AAAA,QAEA;AAAA,8BAAC,YAAY,QAAZ,EACC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,UACE,kBAAkB,aAAa,kBAAkB;AAAA,cAGnD;AAAA,gBAAC;AAAA;AAAA,kBACC,gBAAe;AAAA,kBACf,IAAG;AAAA,kBACH,aAAY;AAAA;AAAA,cACd;AAAA;AAAA,UACF,GACF;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAO;AAAA,cACP,SAAS,kBAAkB;AAAA,cAC3B,MAAM,kBAAkB;AAAA,cACxB,QAAQ;AAAA,cAER,8BAAC,UAAO,SAAQ,eAAc,MAAK,UACjC;AAAA,gBAAC;AAAA;AAAA,kBACC,gBAAe;AAAA,kBACf,IAAG;AAAA,kBACH,aAAY;AAAA;AAAA,cACd,GACF;AAAA;AAAA,UACF;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
@@ -10,6 +10,7 @@ import {
10
10
  import { useQueryClient } from "@tanstack/react-query";
11
11
  import { SaveButton } from "./save-button.js";
12
12
  import { parseUserAgent } from "./utils.js";
13
+ import { Translation } from "./i18n/translation.js";
13
14
  function LogoutDialog({
14
15
  children,
15
16
  session,
@@ -34,14 +35,23 @@ function LogoutDialog({
34
35
  });
35
36
  };
36
37
  return /* @__PURE__ */ jsx(AlertDialog.Root, { open, onOpenChange, ...props, children: /* @__PURE__ */ jsxs(AlertDialog.Content, { maxWidth: "480px", children: [
37
- /* @__PURE__ */ jsx(AlertDialog.Title, { children: "Sign out of device?" }),
38
- /* @__PURE__ */ jsxs(AlertDialog.Description, { children: [
39
- "You will be signed out of ",
40
- /* @__PURE__ */ jsxs(Strong, { children: [
41
- device,
42
- "."
43
- ] })
44
- ] }),
38
+ /* @__PURE__ */ jsx(AlertDialog.Title, { children: /* @__PURE__ */ jsx(
39
+ Translation,
40
+ {
41
+ defaultMessage: "Sign out of device?",
42
+ id: "Jic5nB",
43
+ description: "Dialog title asking to confirm signing out of a device"
44
+ }
45
+ ) }),
46
+ /* @__PURE__ */ jsx(AlertDialog.Description, { children: /* @__PURE__ */ jsx(
47
+ Translation,
48
+ {
49
+ defaultMessage: "You will be signed out of {device}.",
50
+ id: "diFnRK",
51
+ description: "Description explaining the user will be signed out of a specific device",
52
+ values: { device: /* @__PURE__ */ jsx(Strong, { children: device }) }
53
+ }
54
+ ) }),
45
55
  /* @__PURE__ */ jsx(Flex, { gap: "3", justify: "end", mt: "5", asChild: true, children: /* @__PURE__ */ jsxs(
46
56
  "form",
47
57
  {
@@ -55,7 +65,14 @@ function LogoutDialog({
55
65
  {
56
66
  variant: "secondary",
57
67
  disabled: revokeSession.isPending || revokeSession.isSuccess,
58
- children: "Cancel"
68
+ children: /* @__PURE__ */ jsx(
69
+ Translation,
70
+ {
71
+ defaultMessage: "Cancel",
72
+ id: "KjY2RX",
73
+ description: "Button to cancel the logout action"
74
+ }
75
+ )
59
76
  }
60
77
  ) }),
61
78
  /* @__PURE__ */ jsx(
@@ -65,7 +82,14 @@ function LogoutDialog({
65
82
  loading: revokeSession.isPending,
66
83
  done: revokeSession.isSuccess,
67
84
  onDone: handleDone,
68
- children: /* @__PURE__ */ jsx(Button, { variant: "destructive", type: "submit", children: "Sign out" })
85
+ children: /* @__PURE__ */ jsx(Button, { variant: "destructive", type: "submit", children: /* @__PURE__ */ jsx(
86
+ Translation,
87
+ {
88
+ defaultMessage: "Sign out",
89
+ id: "tRJt/S",
90
+ description: "Button to confirm signing out of device"
91
+ }
92
+ ) })
69
93
  }
70
94
  )
71
95
  ]
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/logout-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Flex, Strong } from \"@radix-ui/themes\";\nimport { type ReactNode } from \"react\";\nimport { AlertDialog, Button } from \"./elements.js\";\nimport {\n ActiveSession,\n getSessionsQueryKey,\n useRevokeSession,\n} from \"../api/endpoint.js\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { SaveButton } from \"./save-button.js\";\nimport { parseUserAgent } from \"./utils.js\";\n\ninterface LogoutDialogProps extends AlertDialog.RootProps {\n children?: ReactNode;\n session: ActiveSession;\n}\n\nexport function LogoutDialog({\n children,\n session,\n open,\n onOpenChange,\n ...props\n}: LogoutDialogProps) {\n const client = useQueryClient();\n const userAgent = parseUserAgent(session.userAgent);\n const device = userAgent.pretty;\n\n const revokeSession = useRevokeSession();\n\n const handleDone = React.useCallback(() => {\n onOpenChange?.(false);\n\n client.invalidateQueries({\n queryKey: getSessionsQueryKey(),\n exact: false,\n });\n }, [onOpenChange, client]);\n\n const onSubmitForm = () => {\n revokeSession.mutate({\n sessionId: session.id,\n });\n };\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>\n <AlertDialog.Content maxWidth=\"480px\">\n <AlertDialog.Title>Sign out of device?</AlertDialog.Title>\n <AlertDialog.Description>\n You will be signed out of <Strong>{device}.</Strong>\n </AlertDialog.Description>\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n disabled={revokeSession.isPending || revokeSession.isSuccess}\n >\n Cancel\n </Button>\n </AlertDialog.Cancel>\n\n <SaveButton\n asChild\n loading={revokeSession.isPending}\n done={revokeSession.isSuccess}\n onDone={handleDone}\n >\n <Button variant=\"destructive\" type=\"submit\">\n Sign out\n </Button>\n </SaveButton>\n </form>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n}\n"],"mappings":";AAmDQ,cAE4B,YAF5B;AAjDR,YAAY,WAAW;AACvB,SAAS,MAAM,cAAc;AAE7B,SAAS,aAAa,cAAc;AACpC;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAOxB,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,QAAM,SAAS,eAAe;AAC9B,QAAM,YAAY,eAAe,QAAQ,SAAS;AAClD,QAAM,SAAS,UAAU;AAEzB,QAAM,gBAAgB,iBAAiB;AAEvC,QAAM,aAAa,MAAM,YAAY,MAAM;AACzC,mBAAe,KAAK;AAEpB,WAAO,kBAAkB;AAAA,MACvB,UAAU,oBAAoB;AAAA,MAC9B,OAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,cAAc,MAAM,CAAC;AAEzB,QAAM,eAAe,MAAM;AACzB,kBAAc,OAAO;AAAA,MACnB,WAAW,QAAQ;AAAA,IACrB,CAAC;AAAA,EACH;AAEA,SACE,oBAAC,YAAY,MAAZ,EAAiB,MAAY,cAA6B,GAAG,OAC5D,+BAAC,YAAY,SAAZ,EAAoB,UAAS,SAC5B;AAAA,wBAAC,YAAY,OAAZ,EAAkB,iCAAmB;AAAA,IACtC,qBAAC,YAAY,aAAZ,EAAwB;AAAA;AAAA,MACG,qBAAC,UAAQ;AAAA;AAAA,QAAO;AAAA,SAAC;AAAA,OAC7C;AAAA,IAEA,oBAAC,QAAK,KAAI,KAAI,SAAQ,OAAM,IAAG,KAAI,SAAO,MACxC;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,CAAC,UAAU;AACnB,gBAAM,eAAe;AACrB,uBAAa;AAAA,QACf;AAAA,QAEA;AAAA,8BAAC,YAAY,QAAZ,EACC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,UAAU,cAAc,aAAa,cAAc;AAAA,cACpD;AAAA;AAAA,UAED,GACF;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAO;AAAA,cACP,SAAS,cAAc;AAAA,cACvB,MAAM,cAAc;AAAA,cACpB,QAAQ;AAAA,cAER,8BAAC,UAAO,SAAQ,eAAc,MAAK,UAAS,sBAE5C;AAAA;AAAA,UACF;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/logout-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Flex, Strong } from \"@radix-ui/themes\";\nimport { type ReactNode } from \"react\";\nimport { AlertDialog, Button } from \"./elements.js\";\nimport {\n ActiveSession,\n getSessionsQueryKey,\n useRevokeSession,\n} from \"../api/endpoint.js\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { SaveButton } from \"./save-button.js\";\nimport { parseUserAgent } from \"./utils.js\";\nimport { Translation } from \"./i18n/translation.js\";\n\ninterface LogoutDialogProps extends AlertDialog.RootProps {\n children?: ReactNode;\n session: ActiveSession;\n}\n\nexport function LogoutDialog({\n children,\n session,\n open,\n onOpenChange,\n ...props\n}: LogoutDialogProps) {\n const client = useQueryClient();\n const userAgent = parseUserAgent(session.userAgent);\n const device = userAgent.pretty;\n\n const revokeSession = useRevokeSession();\n\n const handleDone = React.useCallback(() => {\n onOpenChange?.(false);\n\n client.invalidateQueries({\n queryKey: getSessionsQueryKey(),\n exact: false,\n });\n }, [onOpenChange, client]);\n\n const onSubmitForm = () => {\n revokeSession.mutate({\n sessionId: session.id,\n });\n };\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange} {...props}>\n <AlertDialog.Content maxWidth=\"480px\">\n <AlertDialog.Title>\n <Translation\n defaultMessage=\"Sign out of device?\"\n id=\"Jic5nB\"\n description=\"Dialog title asking to confirm signing out of a device\"\n />\n </AlertDialog.Title>\n <AlertDialog.Description>\n <Translation\n defaultMessage=\"You will be signed out of {device}.\"\n id=\"diFnRK\"\n description=\"Description explaining the user will be signed out of a specific device\"\n values={{ device: <Strong>{device}</Strong> }}\n />\n </AlertDialog.Description>\n\n <Flex gap=\"3\" justify=\"end\" mt=\"5\" asChild>\n <form\n onSubmit={(event) => {\n event.preventDefault();\n onSubmitForm();\n }}\n >\n <AlertDialog.Cancel>\n <Button\n variant=\"secondary\"\n disabled={revokeSession.isPending || revokeSession.isSuccess}\n >\n <Translation\n defaultMessage=\"Cancel\"\n id=\"KjY2RX\"\n description=\"Button to cancel the logout action\"\n />\n </Button>\n </AlertDialog.Cancel>\n\n <SaveButton\n asChild\n loading={revokeSession.isPending}\n done={revokeSession.isSuccess}\n onDone={handleDone}\n >\n <Button variant=\"destructive\" type=\"submit\">\n <Translation\n defaultMessage=\"Sign out\"\n id=\"tRJt/S\"\n description=\"Button to confirm signing out of device\"\n />\n </Button>\n </SaveButton>\n </form>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n}\n"],"mappings":";AAqDU,cAgBA,YAhBA;AAnDV,YAAY,WAAW;AACvB,SAAS,MAAM,cAAc;AAE7B,SAAS,aAAa,cAAc;AACpC;AAAA,EAEE;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAC/B,SAAS,mBAAmB;AAOrB,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsB;AACpB,QAAM,SAAS,eAAe;AAC9B,QAAM,YAAY,eAAe,QAAQ,SAAS;AAClD,QAAM,SAAS,UAAU;AAEzB,QAAM,gBAAgB,iBAAiB;AAEvC,QAAM,aAAa,MAAM,YAAY,MAAM;AACzC,mBAAe,KAAK;AAEpB,WAAO,kBAAkB;AAAA,MACvB,UAAU,oBAAoB;AAAA,MAC9B,OAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,cAAc,MAAM,CAAC;AAEzB,QAAM,eAAe,MAAM;AACzB,kBAAc,OAAO;AAAA,MACnB,WAAW,QAAQ;AAAA,IACrB,CAAC;AAAA,EACH;AAEA,SACE,oBAAC,YAAY,MAAZ,EAAiB,MAAY,cAA6B,GAAG,OAC5D,+BAAC,YAAY,SAAZ,EAAoB,UAAS,SAC5B;AAAA,wBAAC,YAAY,OAAZ,EACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,IACA,oBAAC,YAAY,aAAZ,EACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA,QACZ,QAAQ,EAAE,QAAQ,oBAAC,UAAQ,kBAAO,EAAU;AAAA;AAAA,IAC9C,GACF;AAAA,IAEA,oBAAC,QAAK,KAAI,KAAI,SAAQ,OAAM,IAAG,KAAI,SAAO,MACxC;AAAA,MAAC;AAAA;AAAA,QACC,UAAU,CAAC,UAAU;AACnB,gBAAM,eAAe;AACrB,uBAAa;AAAA,QACf;AAAA,QAEA;AAAA,8BAAC,YAAY,QAAZ,EACC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,UAAU,cAAc,aAAa,cAAc;AAAA,cAEnD;AAAA,gBAAC;AAAA;AAAA,kBACC,gBAAe;AAAA,kBACf,IAAG;AAAA,kBACH,aAAY;AAAA;AAAA,cACd;AAAA;AAAA,UACF,GACF;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAO;AAAA,cACP,SAAS,cAAc;AAAA,cACvB,MAAM,cAAc;AAAA,cACpB,QAAQ;AAAA,cAER,8BAAC,UAAO,SAAQ,eAAc,MAAK,UACjC;AAAA,gBAAC;AAAA;AAAA,kBACC,gBAAe;AAAA,kBACf,IAAG;AAAA,kBACH,aAAY;AAAA;AAAA,cACd,GACF;AAAA;AAAA,UACF;AAAA;AAAA;AAAA,IACF,GACF;AAAA,KACF,GACF;AAEJ;","names":[]}
@@ -20,6 +20,8 @@ import {
20
20
  DropdownMenu
21
21
  } from "./elements.js";
22
22
  import { unstable_useWidgetsInvalidator as useWidgetsInvalidator } from "../utils.js";
23
+ import { Translation } from "./i18n/translation.js";
24
+ import { useTranslation } from "./i18n/use-translation.js";
23
25
  const OrganizationSwitcher = ({
24
26
  organizations,
25
27
  switchToOrganization,
@@ -113,7 +115,14 @@ const OrganizationSwitcher = ({
113
115
  truncateBehavior
114
116
  }
115
117
  ),
116
- organization.current && /* @__PURE__ */ jsx(VisuallyHidden, { children: " (current)" }),
118
+ organization.current && /* @__PURE__ */ jsx(VisuallyHidden, { children: /* @__PURE__ */ jsx(
119
+ Translation,
120
+ {
121
+ defaultMessage: "(current)",
122
+ id: "daFXTP",
123
+ description: "Label for screen readers indicating current organization"
124
+ }
125
+ ) }),
117
126
  /* @__PURE__ */ jsx(
118
127
  Flex,
119
128
  {
@@ -163,7 +172,8 @@ function OrganizationSwitcherError({
163
172
  variant,
164
173
  ...domProps
165
174
  }) {
166
- const { heading } = getErrorMessage(error);
175
+ const translate = useTranslation();
176
+ const { heading } = getErrorMessage(error, translate);
167
177
  return /* @__PURE__ */ jsx(
168
178
  Button,
169
179
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/organization-switcher.tsx"],"sourcesContent":["\"use client\";\n\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport {\n Box,\n ChevronDownIcon,\n Flex,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport type { OrganizationInfo } from \"../api/endpoint.js\";\nimport cx from \"clsx\";\nimport {\n getDomProps,\n isPromiseLike,\n type WidgetRootDomProps,\n type WidgetRootState,\n} from \"./utils.js\";\nimport { getErrorMessage } from \"./generic-error.js\";\nimport {\n Button,\n type ButtonProps,\n Skeleton,\n DropdownMenu,\n} from \"./elements.js\";\nimport { unstable_useWidgetsInvalidator as useWidgetsInvalidator } from \"../utils.js\";\n\ntype OrganizationSwitcherVariant = \"ghost\" | \"outline\";\n\n// Rename all uses of `org` to `organization`\ninterface OrganizationSwitcherPassthroughProps extends WidgetRootDomProps {\n switchToOrganization: ({\n organizationId,\n }: {\n organizationId: string;\n }) => void | Promise<void>;\n // Simple props to affect the overall style\n variant?: OrganizationSwitcherVariant;\n organizationLabel?: string | null;\n children?: React.ReactNode;\n /**\n * Choose where to truncate organization name in the trigger and dropdown\n * items.\n *\n * - `right`: Truncate the right side of the organization name\n * - `middle`: Truncate the middle of the organization name, trying to keep\n * words whole\n */\n truncateBehavior?: \"right\" | \"middle\";\n}\n\ninterface OrganizationSwitcherProps\n extends OrganizationSwitcherPassthroughProps {\n organizations: OrganizationInfo[];\n}\n\nconst OrganizationSwitcher: React.FC<OrganizationSwitcherProps> = ({\n organizations,\n switchToOrganization,\n variant,\n organizationLabel = \"Organizations\",\n truncateBehavior = \"right\",\n children,\n ...domProps\n}) => {\n const currentOrganization = organizations.find(\n (organization) => organization.current,\n );\n const invalidateAllWidgets = useWidgetsInvalidator();\n\n // TODO: Possible if the user has no organizations - we should figure out what\n // to do in this case\n if (!currentOrganization) {\n return null;\n }\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <Button\n variant=\"secondary\"\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"resolved\", {\n ...domProps,\n // TODO: Remove `OrganizationSwitcherTrigger` in the next major\n // version. This should follow conventions of all other widgets\n // using classnames in getWidgetRootDomProps.\n className: cx(domProps.className, \"OrganizationSwitcherTrigger\"),\n })}\n >\n <Flex\n align=\"center\"\n justify=\"between\"\n gap=\"2\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n minWidth=\"0\"\n >\n <TruncatedOrganizationName\n organizationName={currentOrganization.name}\n truncateBehavior={truncateBehavior}\n />\n <Flex asChild flexShrink=\"0\">\n <DropdownMenu.TriggerIcon />\n </Flex>\n </Flex>\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n <DropdownMenu.Group>\n {organizationLabel ? (\n <DropdownMenu.Label>\n <Text>{organizationLabel}</Text>\n </DropdownMenu.Label>\n ) : null}\n {organizations.map((organization) => (\n <Flex\n key={organization.id}\n asChild\n pr=\"2\"\n maxWidth=\"280px\"\n minWidth=\"180px\"\n >\n <DropdownMenu.Item\n onClick={() => {\n if (organization.id !== currentOrganization.id) {\n const result = switchToOrganization({\n organizationId: organization.id,\n });\n if (isPromiseLike(result)) {\n result.then(invalidateAllWidgets);\n } else {\n invalidateAllWidgets();\n }\n }\n }}\n >\n <Flex\n justify=\"between\"\n align=\"center\"\n gap=\"4\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n >\n <TruncatedOrganizationName\n organizationName={organization.name}\n truncateBehavior={truncateBehavior}\n />\n {organization.current && (\n <VisuallyHidden> (current)</VisuallyHidden>\n )}\n <Flex\n aria-hidden\n align=\"center\"\n justify=\"center\"\n flexShrink=\"0\"\n >\n {organization.current ? (\n <CheckIcon width=\"18px\" height=\"18px\" />\n ) : (\n // make the extra space for\n <Box width=\"18px\" height=\"18px\" />\n )}\n </Flex>\n </Flex>\n </DropdownMenu.Item>\n </Flex>\n ))}\n </DropdownMenu.Group>\n {children}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n};\n\ninterface OrganizationSwitcherLoadingProps extends WidgetRootDomProps {\n variant?: OrganizationSwitcherVariant;\n}\n\nconst OrganizationSwitcherLoading: React.FC<\n OrganizationSwitcherLoadingProps\n> = ({ variant, ...props }: OrganizationSwitcherLoadingProps) => {\n return (\n // Always need DropdownMenu.Root to wrap children than may include\n <Button\n variant=\"secondary\"\n disabled\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"loading\", props)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Skeleton>\n <Text>Loading...</Text>\n </Skeleton>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n};\n\ninterface OrganizationSwitcherErrorProps extends WidgetRootDomProps {\n error: unknown;\n variant?: OrganizationSwitcherVariant;\n}\n\nfunction OrganizationSwitcherError({\n error,\n variant,\n ...domProps\n}: OrganizationSwitcherErrorProps) {\n const { heading } = getErrorMessage(error);\n\n return (\n <Button\n variant=\"secondary\"\n disabled\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"error\", domProps)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Text>{heading}</Text>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n}\n\nconst MAX_TRUNCATED_SUFFIX_LENGTH = 10;\nconst MIN_TRUNCATED_SUFFIX_LENGTH = 3;\n\nconst WHITE_SPACE_REGEX = /\\s/;\n\nconst getSplitPosition = (organizationName: string) => {\n if (organizationName.length <= MAX_TRUNCATED_SUFFIX_LENGTH) {\n return organizationName.length;\n }\n\n for (\n let i = organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n i < organizationName.length - MIN_TRUNCATED_SUFFIX_LENGTH;\n i++\n ) {\n if (WHITE_SPACE_REGEX.test(organizationName[i - 1])) {\n return i;\n }\n }\n\n return organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n};\n\nconst splitOrganizationName = (organizationName: string) => {\n const splitPosition = getSplitPosition(organizationName);\n return [\n organizationName.slice(0, splitPosition),\n organizationName.slice(splitPosition),\n ];\n};\n\nconst TruncatedOrganizationName = ({\n organizationName,\n truncateBehavior,\n}: {\n organizationName: string;\n truncateBehavior: \"right\" | \"middle\";\n}) => {\n if (truncateBehavior === \"right\") {\n return <Text truncate>{organizationName}</Text>;\n }\n\n const [organizationNameLeft, organizationNameRight] =\n splitOrganizationName(organizationName);\n\n return (\n <Flex overflow=\"hidden\">\n <VisuallyHidden>\n <Text>{organizationName}</Text>\n </VisuallyHidden>\n <Text aria-hidden truncate style={{ whiteSpace: \"pre\" }}>\n {organizationNameLeft}\n </Text>\n <Text aria-hidden>{organizationNameRight}</Text>\n </Flex>\n );\n};\n\nfunction mapVariantProps(variant?: OrganizationSwitcherVariant): ButtonProps {\n const variantProps: ButtonProps = {};\n // Passing `undefined` to the variant prop will result in overrides to props we\n // set internally. This should be addressed in Radix Themes, but we can\n // explicitly set it only when it's provided and _not_ undefined.\n if (variant) {\n variantProps.unsafe_radixVariant = variant;\n }\n return variantProps;\n}\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"organization-switcher\",\n widgetState: state,\n });\n}\n\nexport type {\n OrganizationSwitcherProps,\n OrganizationSwitcherLoadingProps,\n OrganizationSwitcherErrorProps,\n /** @internal */\n OrganizationSwitcherPassthroughProps,\n};\nexport {\n OrganizationSwitcher,\n OrganizationSwitcherLoading,\n OrganizationSwitcherError,\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/organization-switcher.tsx"],"sourcesContent":["\"use client\";\n\nimport { CheckIcon } from \"@radix-ui/react-icons\";\nimport {\n Box,\n ChevronDownIcon,\n Flex,\n Text,\n VisuallyHidden,\n} from \"@radix-ui/themes\";\nimport type { OrganizationInfo } from \"../api/endpoint.js\";\nimport cx from \"clsx\";\nimport {\n getDomProps,\n isPromiseLike,\n type WidgetRootDomProps,\n type WidgetRootState,\n} from \"./utils.js\";\nimport { getErrorMessage } from \"./generic-error.js\";\nimport {\n Button,\n type ButtonProps,\n Skeleton,\n DropdownMenu,\n} from \"./elements.js\";\nimport { unstable_useWidgetsInvalidator as useWidgetsInvalidator } from \"../utils.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\n\ntype OrganizationSwitcherVariant = \"ghost\" | \"outline\";\n\n// Rename all uses of `org` to `organization`\ninterface OrganizationSwitcherPassthroughProps extends WidgetRootDomProps {\n switchToOrganization: ({\n organizationId,\n }: {\n organizationId: string;\n }) => void | Promise<void>;\n // Simple props to affect the overall style\n variant?: OrganizationSwitcherVariant;\n organizationLabel?: string | null;\n children?: React.ReactNode;\n /**\n * Choose where to truncate organization name in the trigger and dropdown\n * items.\n *\n * - `right`: Truncate the right side of the organization name\n * - `middle`: Truncate the middle of the organization name, trying to keep\n * words whole\n */\n truncateBehavior?: \"right\" | \"middle\";\n}\n\ninterface OrganizationSwitcherProps\n extends OrganizationSwitcherPassthroughProps {\n organizations: OrganizationInfo[];\n}\n\nconst OrganizationSwitcher: React.FC<OrganizationSwitcherProps> = ({\n organizations,\n switchToOrganization,\n variant,\n organizationLabel = \"Organizations\",\n truncateBehavior = \"right\",\n children,\n ...domProps\n}) => {\n const currentOrganization = organizations.find(\n (organization) => organization.current,\n );\n const invalidateAllWidgets = useWidgetsInvalidator();\n\n // TODO: Possible if the user has no organizations - we should figure out what\n // to do in this case\n if (!currentOrganization) {\n return null;\n }\n\n return (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <Button\n variant=\"secondary\"\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"resolved\", {\n ...domProps,\n // TODO: Remove `OrganizationSwitcherTrigger` in the next major\n // version. This should follow conventions of all other widgets\n // using classnames in getWidgetRootDomProps.\n className: cx(domProps.className, \"OrganizationSwitcherTrigger\"),\n })}\n >\n <Flex\n align=\"center\"\n justify=\"between\"\n gap=\"2\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n minWidth=\"0\"\n >\n <TruncatedOrganizationName\n organizationName={currentOrganization.name}\n truncateBehavior={truncateBehavior}\n />\n <Flex asChild flexShrink=\"0\">\n <DropdownMenu.TriggerIcon />\n </Flex>\n </Flex>\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content>\n <DropdownMenu.Group>\n {organizationLabel ? (\n <DropdownMenu.Label>\n <Text>{organizationLabel}</Text>\n </DropdownMenu.Label>\n ) : null}\n {organizations.map((organization) => (\n <Flex\n key={organization.id}\n asChild\n pr=\"2\"\n maxWidth=\"280px\"\n minWidth=\"180px\"\n >\n <DropdownMenu.Item\n onClick={() => {\n if (organization.id !== currentOrganization.id) {\n const result = switchToOrganization({\n organizationId: organization.id,\n });\n if (isPromiseLike(result)) {\n result.then(invalidateAllWidgets);\n } else {\n invalidateAllWidgets();\n }\n }\n }}\n >\n <Flex\n justify=\"between\"\n align=\"center\"\n gap=\"4\"\n flexGrow=\"1\"\n overflow=\"hidden\"\n >\n <TruncatedOrganizationName\n organizationName={organization.name}\n truncateBehavior={truncateBehavior}\n />\n {organization.current && (\n <VisuallyHidden>\n <Translation\n defaultMessage=\"(current)\"\n id=\"daFXTP\"\n description=\"Label for screen readers indicating current organization\"\n />\n </VisuallyHidden>\n )}\n <Flex\n aria-hidden\n align=\"center\"\n justify=\"center\"\n flexShrink=\"0\"\n >\n {organization.current ? (\n <CheckIcon width=\"18px\" height=\"18px\" />\n ) : (\n // make the extra space for\n <Box width=\"18px\" height=\"18px\" />\n )}\n </Flex>\n </Flex>\n </DropdownMenu.Item>\n </Flex>\n ))}\n </DropdownMenu.Group>\n {children}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n );\n};\n\ninterface OrganizationSwitcherLoadingProps extends WidgetRootDomProps {\n variant?: OrganizationSwitcherVariant;\n}\n\nconst OrganizationSwitcherLoading: React.FC<\n OrganizationSwitcherLoadingProps\n> = ({ variant, ...props }: OrganizationSwitcherLoadingProps) => {\n return (\n // Always need DropdownMenu.Root to wrap children than may include\n <Button\n variant=\"secondary\"\n disabled\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"loading\", props)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Skeleton>\n {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}\n <Text>Loading...</Text>\n </Skeleton>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n};\n\ninterface OrganizationSwitcherErrorProps extends WidgetRootDomProps {\n error: unknown;\n variant?: OrganizationSwitcherVariant;\n}\n\nfunction OrganizationSwitcherError({\n error,\n variant,\n ...domProps\n}: OrganizationSwitcherErrorProps) {\n const translate = useTranslation();\n const { heading } = getErrorMessage(error, translate);\n\n return (\n <Button\n variant=\"secondary\"\n disabled\n {...mapVariantProps(variant)}\n {...getWidgetRootDomProps(\"error\", domProps)}\n >\n <Flex align=\"center\" gap=\"2\">\n <Text>{heading}</Text>\n <ChevronDownIcon />\n </Flex>\n </Button>\n );\n}\n\nconst MAX_TRUNCATED_SUFFIX_LENGTH = 10;\nconst MIN_TRUNCATED_SUFFIX_LENGTH = 3;\n\nconst WHITE_SPACE_REGEX = /\\s/;\n\nconst getSplitPosition = (organizationName: string) => {\n if (organizationName.length <= MAX_TRUNCATED_SUFFIX_LENGTH) {\n return organizationName.length;\n }\n\n for (\n let i = organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n i < organizationName.length - MIN_TRUNCATED_SUFFIX_LENGTH;\n i++\n ) {\n if (WHITE_SPACE_REGEX.test(organizationName[i - 1])) {\n return i;\n }\n }\n\n return organizationName.length - MAX_TRUNCATED_SUFFIX_LENGTH;\n};\n\nconst splitOrganizationName = (organizationName: string) => {\n const splitPosition = getSplitPosition(organizationName);\n return [\n organizationName.slice(0, splitPosition),\n organizationName.slice(splitPosition),\n ];\n};\n\nconst TruncatedOrganizationName = ({\n organizationName,\n truncateBehavior,\n}: {\n organizationName: string;\n truncateBehavior: \"right\" | \"middle\";\n}) => {\n if (truncateBehavior === \"right\") {\n return <Text truncate>{organizationName}</Text>;\n }\n\n const [organizationNameLeft, organizationNameRight] =\n splitOrganizationName(organizationName);\n\n return (\n <Flex overflow=\"hidden\">\n <VisuallyHidden>\n <Text>{organizationName}</Text>\n </VisuallyHidden>\n <Text aria-hidden truncate style={{ whiteSpace: \"pre\" }}>\n {organizationNameLeft}\n </Text>\n <Text aria-hidden>{organizationNameRight}</Text>\n </Flex>\n );\n};\n\nfunction mapVariantProps(variant?: OrganizationSwitcherVariant): ButtonProps {\n const variantProps: ButtonProps = {};\n // Passing `undefined` to the variant prop will result in overrides to props we\n // set internally. This should be addressed in Radix Themes, but we can\n // explicitly set it only when it's provided and _not_ undefined.\n if (variant) {\n variantProps.unsafe_radixVariant = variant;\n }\n return variantProps;\n}\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"organization-switcher\",\n widgetState: state,\n });\n}\n\nexport type {\n OrganizationSwitcherProps,\n OrganizationSwitcherLoadingProps,\n OrganizationSwitcherErrorProps,\n /** @internal */\n OrganizationSwitcherPassthroughProps,\n};\nexport {\n OrganizationSwitcher,\n OrganizationSwitcherLoading,\n OrganizationSwitcherError,\n};\n"],"mappings":"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","names":[]}