@rapidmx/web-client 0.30.0 → 0.32.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 (402) hide show
  1. package/apps/admin/audit-log/index.tsx +3 -3
  2. package/apps/admin/branding/index.tsx +3 -3
  3. package/apps/admin/data-requests/index.tsx +18 -7
  4. package/apps/admin/distribution-lists/[uid].tsx +3 -3
  5. package/apps/admin/distribution-lists/index.tsx +3 -3
  6. package/apps/admin/distribution-lists/new/index.tsx +3 -3
  7. package/apps/admin/domains/[uid].tsx +6 -5
  8. package/apps/admin/domains/index.tsx +3 -3
  9. package/apps/admin/domains/new/index.tsx +3 -3
  10. package/apps/admin/escrow-scopes/[uid].tsx +11 -5
  11. package/apps/admin/escrow-scopes/index.tsx +3 -3
  12. package/apps/admin/escrow-scopes/new/index.tsx +9 -3
  13. package/apps/admin/index.tsx +4 -4
  14. package/apps/admin/ingest-queue/index.tsx +3 -3
  15. package/apps/admin/mailboxes/[uid].tsx +15 -7
  16. package/apps/admin/quarantine/index.tsx +4 -4
  17. package/apps/admin/retention-policy/index.tsx +3 -3
  18. package/apps/admin/signing-certificates/index.tsx +3 -3
  19. package/apps/admin/transport-rules/[uid].tsx +4 -4
  20. package/apps/admin/transport-rules/index.tsx +3 -3
  21. package/apps/admin/transport-rules/new/index.tsx +3 -3
  22. package/apps/escrow/matters/[uid].tsx +26 -2
  23. package/apps/escrow/matters/new/index.tsx +4 -0
  24. package/apps/shared/calendar/calendarLiveUpdates.ts +11 -10
  25. package/apps/shared/calendar/useCalendarReminders.ts +2 -0
  26. package/apps/shared/components/admin/ActionAlert.tsx +32 -0
  27. package/apps/shared/components/admin/diagnostics/InformationPanel.tsx +3 -3
  28. package/apps/shared/components/admin/diagnostics/InstalledPlugins.tsx +1 -1
  29. package/apps/shared/components/admin/diagnostics/LogsPanel.tsx +1 -1
  30. package/apps/shared/components/admin/diagnostics/RuntimePanel.tsx +1 -1
  31. package/apps/shared/components/admin/diagnostics/SystemPanel.tsx +1 -1
  32. package/apps/shared/components/admin/diagnostics/diagnosticsApi.ts +2 -2
  33. package/apps/shared/components/admin/distributionLists/MemberListCard.tsx +4 -4
  34. package/apps/shared/components/admin/elevation.ts +19 -0
  35. package/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.tsx +58 -3
  36. package/apps/shared/components/admin/layout/AdminShell.tsx +6 -1
  37. package/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.tsx +3 -3
  38. package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +4 -4
  39. package/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.tsx +4 -4
  40. package/apps/shared/components/admin/mailboxes/ResourceSettingsCard.tsx +3 -3
  41. package/apps/shared/components/admin/mailboxes/ShareAccessCard.tsx +6 -6
  42. package/apps/shared/components/admin/settings/BrandingForm.tsx +22 -9
  43. package/apps/shared/components/admin/settings/DomainDnsSetup.tsx +4 -4
  44. package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +33 -4
  45. package/apps/shared/components/admin/settings/LoadedSettingsForm.tsx +3 -3
  46. package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +8 -3
  47. package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +3 -3
  48. package/apps/shared/components/admin/settings/PluginsManager.tsx +195 -46
  49. package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +25 -12
  50. package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +40 -7
  51. package/apps/shared/components/admin/setup/SetupWizard.tsx +8 -6
  52. package/apps/shared/components/admin/signOut.ts +3 -0
  53. package/apps/shared/components/admin/usePagedList.tsx +2 -2
  54. package/apps/shared/components/calendar/DescriptionEditor.tsx +2 -1
  55. package/apps/shared/components/calendar/EventDetails.tsx +34 -8
  56. package/apps/shared/components/calendar/EventEditor.tsx +90 -40
  57. package/apps/shared/components/calendar/EventFormParts.tsx +5 -2
  58. package/apps/shared/components/calendar/EventMatchNav.tsx +14 -2
  59. package/apps/shared/components/calendar/EventModal.tsx +25 -1
  60. package/apps/shared/components/calendar/FindATime.tsx +10 -2
  61. package/apps/shared/components/calendar/ListView.tsx +99 -25
  62. package/apps/shared/components/calendar/RecurrenceEditor.tsx +19 -8
  63. package/apps/shared/components/calendar/SplitDayView.tsx +14 -18
  64. package/apps/shared/components/calendar/TaskQuickForm.tsx +3 -2
  65. package/apps/shared/components/calendar/TimeGridView.tsx +35 -19
  66. package/apps/shared/components/calendar/gridLayout.ts +94 -0
  67. package/apps/shared/components/calendar/layout/CalendarShell.tsx +1 -1
  68. package/apps/shared/components/calendar/timePicker.ts +5 -2
  69. package/apps/shared/components/contacts/ContactCard.tsx +15 -4
  70. package/apps/shared/components/contacts/ContactDetailPane.tsx +54 -15
  71. package/apps/shared/components/contacts/ContactForm.tsx +61 -17
  72. package/apps/shared/components/contacts/ContactPhotoEditor.tsx +88 -0
  73. package/apps/shared/components/contacts/ContactPhotoField.tsx +36 -39
  74. package/apps/shared/components/contacts/layout/ContactsShell.tsx +1 -1
  75. package/apps/shared/components/contacts/participantDetails.ts +18 -1
  76. package/apps/shared/components/layout/AppShell.tsx +9 -0
  77. package/apps/shared/components/layout/KeyEnrollmentGate.tsx +9 -4
  78. package/apps/shared/components/layout/MailboxProvisioning.tsx +31 -3
  79. package/apps/shared/components/layout/RecoveryCodeUnlock.tsx +4 -2
  80. package/apps/shared/components/mail/ConversationList.tsx +49 -6
  81. package/apps/shared/components/mail/ConversationThreadPane.tsx +1 -1
  82. package/apps/shared/components/mail/MenuButton.tsx +3 -400
  83. package/apps/shared/components/mail/MessageDetailPane.tsx +16 -13
  84. package/apps/shared/components/mail/compose/ComposeToolbar.tsx +11 -1
  85. package/apps/shared/components/mail/compose/ComposeWindow.tsx +57 -11
  86. package/apps/shared/components/mail/compose/GifPicker.tsx +10 -4
  87. package/apps/shared/components/mail/compose/RecipientInput.tsx +9 -7
  88. package/apps/shared/components/mail/compose/composeFlushRegistry.ts +14 -1
  89. package/apps/shared/components/mail/compose/encryptionRequirement.ts +5 -0
  90. package/apps/shared/components/mail/compose/quotedBody.ts +31 -6
  91. package/apps/shared/components/mail/layout/MailShell.tsx +1 -1
  92. package/apps/shared/components/mail/reading/MessageBody.tsx +13 -7
  93. package/apps/shared/components/mail/reading/bodyContent.ts +2 -0
  94. package/apps/shared/components/mail/reading/bodyHtml.ts +25 -2
  95. package/apps/shared/components/mail/writableMailboxes.ts +2 -0
  96. package/apps/shared/components/rules/RuleBuilder.tsx +11 -2
  97. package/apps/shared/components/settings/GravatarSetting.tsx +27 -0
  98. package/apps/shared/components/settings/layout/SettingsShell.tsx +1 -1
  99. package/apps/shared/components/tasks/dueDate.ts +29 -0
  100. package/apps/shared/components/tasks/layout/TasksShell.tsx +1 -1
  101. package/apps/shared/mail/decryptedMessages.ts +51 -2
  102. package/apps/shared/mail/listSnapshots.ts +2 -0
  103. package/apps/shared/mail/outbox/sendDecision.ts +14 -3
  104. package/apps/shared/mail/outbox/sendJob.ts +5 -0
  105. package/apps/shared/mail/useMailLiveUpdates.ts +7 -1
  106. package/apps/shared/mail/usePermanentDelete.tsx +3 -1
  107. package/apps/shared/notifications/apiErrors.ts +2 -0
  108. package/apps/shared/notifications/preferences.ts +1 -1
  109. package/apps/shared/notifications/store.ts +3 -1
  110. package/apps/shared/plugins/pluginNav.ts +4 -2
  111. package/apps/www/calendar/index.tsx +24 -12
  112. package/apps/www/contacts/[uid].tsx +6 -1
  113. package/apps/www/contacts/index.tsx +66 -12
  114. package/apps/www/index.tsx +91 -28
  115. package/apps/www/messages/[uid].tsx +8 -3
  116. package/apps/www/settings/auto-reply/index.tsx +13 -0
  117. package/apps/www/settings/blocked-senders/index.tsx +4 -0
  118. package/apps/www/settings/encryption/index.tsx +66 -4
  119. package/apps/www/settings/privacy/index.tsx +4 -1
  120. package/apps/www/settings/profile/index.tsx +12 -1
  121. package/apps/www/settings/sharing/index.tsx +11 -1
  122. package/apps/www/settings/signatures/[uid].tsx +6 -4
  123. package/apps/www/tasks/index.tsx +97 -29
  124. package/dist/apps/admin/audit-log/index.js +3 -3
  125. package/dist/apps/admin/branding/index.js +3 -3
  126. package/dist/apps/admin/data-requests/index.js +17 -7
  127. package/dist/apps/admin/distribution-lists/[uid].js +3 -3
  128. package/dist/apps/admin/distribution-lists/index.js +3 -3
  129. package/dist/apps/admin/distribution-lists/new/index.js +3 -3
  130. package/dist/apps/admin/domains/[uid].js +6 -5
  131. package/dist/apps/admin/domains/index.js +3 -3
  132. package/dist/apps/admin/domains/new/index.js +3 -3
  133. package/dist/apps/admin/escrow-scopes/[uid].js +11 -6
  134. package/dist/apps/admin/escrow-scopes/index.js +3 -3
  135. package/dist/apps/admin/escrow-scopes/new/index.js +9 -4
  136. package/dist/apps/admin/index.js +4 -4
  137. package/dist/apps/admin/ingest-queue/index.js +3 -3
  138. package/dist/apps/admin/mailboxes/[uid].js +15 -7
  139. package/dist/apps/admin/quarantine/index.js +4 -4
  140. package/dist/apps/admin/retention-policy/index.js +3 -3
  141. package/dist/apps/admin/signing-certificates/index.js +3 -3
  142. package/dist/apps/admin/transport-rules/[uid].js +4 -4
  143. package/dist/apps/admin/transport-rules/index.js +3 -3
  144. package/dist/apps/admin/transport-rules/new/index.js +3 -3
  145. package/dist/apps/escrow/matters/[uid].js +8 -3
  146. package/dist/apps/escrow/matters/new/index.js +4 -0
  147. package/dist/apps/shared/calendar/calendarLiveUpdates.d.ts +11 -7
  148. package/dist/apps/shared/calendar/calendarLiveUpdates.js +10 -9
  149. package/dist/apps/shared/calendar/useCalendarReminders.js +2 -0
  150. package/dist/apps/shared/components/admin/ActionAlert.d.ts +13 -0
  151. package/dist/apps/shared/components/admin/ActionAlert.js +24 -0
  152. package/dist/apps/shared/components/admin/diagnostics/InformationPanel.js +2 -2
  153. package/dist/apps/shared/components/admin/diagnostics/InstalledPlugins.js +1 -1
  154. package/dist/apps/shared/components/admin/diagnostics/LogsPanel.js +1 -1
  155. package/dist/apps/shared/components/admin/diagnostics/RuntimePanel.js +1 -1
  156. package/dist/apps/shared/components/admin/diagnostics/SystemPanel.js +1 -1
  157. package/dist/apps/shared/components/admin/diagnostics/diagnosticsApi.d.ts +2 -2
  158. package/dist/apps/shared/components/admin/distributionLists/MemberListCard.js +4 -4
  159. package/dist/apps/shared/components/admin/elevation.d.ts +9 -0
  160. package/dist/apps/shared/components/admin/elevation.js +16 -0
  161. package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.d.ts +2 -0
  162. package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js +41 -1
  163. package/dist/apps/shared/components/admin/layout/AdminShell.js +2 -1
  164. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.js +3 -3
  165. package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.js +4 -4
  166. package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.js +4 -4
  167. package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.js +3 -3
  168. package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +6 -6
  169. package/dist/apps/shared/components/admin/settings/BrandingForm.js +17 -7
  170. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +4 -4
  171. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +17 -5
  172. package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.js +3 -3
  173. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +8 -3
  174. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +3 -3
  175. package/dist/apps/shared/components/admin/settings/PluginsManager.js +103 -18
  176. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +17 -10
  177. package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +18 -8
  178. package/dist/apps/shared/components/admin/setup/SetupWizard.js +8 -6
  179. package/dist/apps/shared/components/admin/signOut.js +3 -0
  180. package/dist/apps/shared/components/admin/usePagedList.js +2 -2
  181. package/dist/apps/shared/components/calendar/DescriptionEditor.js +2 -1
  182. package/dist/apps/shared/components/calendar/EventDetails.d.ts +3 -1
  183. package/dist/apps/shared/components/calendar/EventDetails.js +7 -4
  184. package/dist/apps/shared/components/calendar/EventEditor.js +81 -33
  185. package/dist/apps/shared/components/calendar/EventFormParts.d.ts +3 -1
  186. package/dist/apps/shared/components/calendar/EventFormParts.js +3 -3
  187. package/dist/apps/shared/components/calendar/EventMatchNav.d.ts +1 -1
  188. package/dist/apps/shared/components/calendar/EventMatchNav.js +12 -2
  189. package/dist/apps/shared/components/calendar/EventModal.js +10 -2
  190. package/dist/apps/shared/components/calendar/FindATime.js +4 -3
  191. package/dist/apps/shared/components/calendar/ListView.d.ts +10 -4
  192. package/dist/apps/shared/components/calendar/ListView.js +92 -27
  193. package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +4 -1
  194. package/dist/apps/shared/components/calendar/RecurrenceEditor.js +15 -10
  195. package/dist/apps/shared/components/calendar/SplitDayView.js +11 -17
  196. package/dist/apps/shared/components/calendar/TaskQuickForm.js +3 -2
  197. package/dist/apps/shared/components/calendar/TimeGridView.js +23 -21
  198. package/dist/apps/shared/components/calendar/gridLayout.d.ts +41 -0
  199. package/dist/apps/shared/components/calendar/gridLayout.js +83 -0
  200. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +1 -1
  201. package/dist/apps/shared/components/calendar/timePicker.js +5 -2
  202. package/dist/apps/shared/components/contacts/ContactCard.js +9 -3
  203. package/dist/apps/shared/components/contacts/ContactDetailPane.d.ts +5 -3
  204. package/dist/apps/shared/components/contacts/ContactDetailPane.js +11 -5
  205. package/dist/apps/shared/components/contacts/ContactForm.js +54 -16
  206. package/dist/apps/shared/components/contacts/ContactPhotoEditor.d.ts +21 -0
  207. package/dist/apps/shared/components/contacts/ContactPhotoEditor.js +56 -0
  208. package/dist/apps/shared/components/contacts/ContactPhotoField.d.ts +7 -4
  209. package/dist/apps/shared/components/contacts/ContactPhotoField.js +19 -21
  210. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +1 -1
  211. package/dist/apps/shared/components/contacts/participantDetails.d.ts +4 -1
  212. package/dist/apps/shared/components/contacts/participantDetails.js +17 -1
  213. package/dist/apps/shared/components/layout/AppShell.js +9 -0
  214. package/dist/apps/shared/components/layout/KeyEnrollmentGate.js +2 -3
  215. package/dist/apps/shared/components/layout/MailboxProvisioning.d.ts +4 -1
  216. package/dist/apps/shared/components/layout/MailboxProvisioning.js +24 -2
  217. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.d.ts +4 -2
  218. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.js +4 -2
  219. package/dist/apps/shared/components/mail/ConversationList.js +49 -6
  220. package/dist/apps/shared/components/mail/ConversationThreadPane.js +1 -1
  221. package/dist/apps/shared/components/mail/MenuButton.d.ts +2 -78
  222. package/dist/apps/shared/components/mail/MenuButton.js +2 -211
  223. package/dist/apps/shared/components/mail/MessageDetailPane.js +10 -6
  224. package/dist/apps/shared/components/mail/compose/ComposeToolbar.d.ts +3 -0
  225. package/dist/apps/shared/components/mail/compose/ComposeToolbar.js +10 -1
  226. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +55 -10
  227. package/dist/apps/shared/components/mail/compose/GifPicker.js +10 -4
  228. package/dist/apps/shared/components/mail/compose/RecipientInput.js +9 -7
  229. package/dist/apps/shared/components/mail/compose/composeFlushRegistry.d.ts +7 -1
  230. package/dist/apps/shared/components/mail/compose/composeFlushRegistry.js +13 -1
  231. package/dist/apps/shared/components/mail/compose/encryptionRequirement.d.ts +5 -0
  232. package/dist/apps/shared/components/mail/compose/quotedBody.js +28 -5
  233. package/dist/apps/shared/components/mail/layout/MailShell.js +1 -1
  234. package/dist/apps/shared/components/mail/reading/MessageBody.js +11 -6
  235. package/dist/apps/shared/components/mail/reading/bodyContent.js +2 -0
  236. package/dist/apps/shared/components/mail/reading/bodyHtml.d.ts +5 -1
  237. package/dist/apps/shared/components/mail/reading/bodyHtml.js +23 -2
  238. package/dist/apps/shared/components/mail/writableMailboxes.js +2 -0
  239. package/dist/apps/shared/components/rules/RuleBuilder.js +9 -1
  240. package/dist/apps/shared/components/settings/GravatarSetting.d.ts +6 -0
  241. package/dist/apps/shared/components/settings/GravatarSetting.js +15 -0
  242. package/dist/apps/shared/components/settings/layout/SettingsShell.js +1 -1
  243. package/dist/apps/shared/components/tasks/dueDate.d.ts +12 -0
  244. package/dist/apps/shared/components/tasks/dueDate.js +26 -0
  245. package/dist/apps/shared/components/tasks/layout/TasksShell.js +1 -1
  246. package/dist/apps/shared/mail/decryptedMessages.d.ts +8 -0
  247. package/dist/apps/shared/mail/decryptedMessages.js +46 -2
  248. package/dist/apps/shared/mail/listSnapshots.js +2 -0
  249. package/dist/apps/shared/mail/outbox/sendDecision.d.ts +6 -3
  250. package/dist/apps/shared/mail/outbox/sendDecision.js +13 -3
  251. package/dist/apps/shared/mail/outbox/sendJob.d.ts +1 -0
  252. package/dist/apps/shared/mail/outbox/sendJob.js +5 -1
  253. package/dist/apps/shared/mail/useMailLiveUpdates.d.ts +3 -0
  254. package/dist/apps/shared/mail/useMailLiveUpdates.js +6 -1
  255. package/dist/apps/shared/mail/usePermanentDelete.d.ts +2 -0
  256. package/dist/apps/shared/mail/usePermanentDelete.js +1 -1
  257. package/dist/apps/shared/notifications/apiErrors.js +2 -0
  258. package/dist/apps/shared/notifications/preferences.d.ts +1 -1
  259. package/dist/apps/shared/notifications/preferences.js +1 -1
  260. package/dist/apps/shared/notifications/store.js +3 -1
  261. package/dist/apps/shared/plugins/pluginNav.d.ts +2 -1
  262. package/dist/apps/shared/plugins/pluginNav.js +4 -2
  263. package/dist/apps/www/calendar/index.js +24 -12
  264. package/dist/apps/www/contacts/[uid].js +6 -2
  265. package/dist/apps/www/contacts/index.js +62 -11
  266. package/dist/apps/www/index.js +85 -30
  267. package/dist/apps/www/messages/[uid].js +8 -3
  268. package/dist/apps/www/settings/auto-reply/index.js +13 -1
  269. package/dist/apps/www/settings/blocked-senders/index.js +4 -0
  270. package/dist/apps/www/settings/encryption/index.js +29 -5
  271. package/dist/apps/www/settings/privacy/index.js +3 -2
  272. package/dist/apps/www/settings/profile/index.js +4 -1
  273. package/dist/apps/www/settings/sharing/index.js +10 -1
  274. package/dist/apps/www/settings/signatures/[uid].js +6 -4
  275. package/dist/apps/www/tasks/index.js +94 -32
  276. package/dist/lib/admin/auditLogApi.js +2 -2
  277. package/dist/lib/admin/distributionListsApi.js +2 -2
  278. package/dist/lib/admin/domainsApi.js +2 -2
  279. package/dist/lib/admin/escrowAuditLogApi.js +2 -2
  280. package/dist/lib/admin/escrowScopesApi.js +2 -2
  281. package/dist/lib/admin/pluginsApi.d.ts +31 -2
  282. package/dist/lib/admin/pluginsApi.js +23 -1
  283. package/dist/lib/admin/retentionPolicyApi.d.ts +3 -0
  284. package/dist/lib/admin/retentionPolicyApi.js +3 -0
  285. package/dist/lib/admin/transportRulesApi.js +2 -2
  286. package/dist/lib/appearance/preferencesApi.d.ts +1 -1
  287. package/dist/lib/appearance/preferencesApi.js +3 -14
  288. package/dist/lib/auth/session.d.ts +51 -12
  289. package/dist/lib/auth/session.js +214 -38
  290. package/dist/lib/branding/brandingApi.d.ts +3 -3
  291. package/dist/lib/branding/brandingApi.js +9 -21
  292. package/dist/lib/calendar/calendarApi.js +3 -1
  293. package/dist/lib/calendar/eventSearch.js +43 -6
  294. package/dist/lib/calendar/freeBusyApi.d.ts +2 -1
  295. package/dist/lib/calendar/freeBusyApi.js +13 -5
  296. package/dist/lib/calendar/recurrence.js +51 -3
  297. package/dist/lib/calendar/useDayKey.d.ts +7 -0
  298. package/dist/lib/calendar/useDayKey.js +43 -0
  299. package/dist/lib/components/avatar/ContactAvatar.d.ts +6 -2
  300. package/dist/lib/components/avatar/ContactAvatar.js +37 -8
  301. package/dist/lib/components/avatar/ContactPhotoAvatar.d.ts +11 -0
  302. package/dist/lib/components/avatar/ContactPhotoAvatar.js +18 -0
  303. package/dist/lib/components/forms/CameraCaptureModal.d.ts +17 -0
  304. package/dist/lib/components/forms/CameraCaptureModal.js +88 -0
  305. package/dist/lib/components/forms/ImageEditBadge.d.ts +28 -0
  306. package/dist/lib/components/forms/ImageEditBadge.js +62 -0
  307. package/dist/lib/components/menus/MenuButton.d.ts +78 -0
  308. package/dist/lib/components/menus/MenuButton.js +219 -0
  309. package/dist/lib/components/navigation/BottomTabBar.d.ts +3 -1
  310. package/dist/lib/components/navigation/BottomTabBar.js +22 -3
  311. package/dist/lib/components/overlays/PopoverPortal.d.ts +2 -1
  312. package/dist/lib/components/overlays/PopoverPortal.js +3 -2
  313. package/dist/lib/components/pickers/TimeZonePicker.js +13 -1
  314. package/dist/lib/contacts/contactsApi.d.ts +5 -2
  315. package/dist/lib/contacts/contactsApi.js +16 -19
  316. package/dist/lib/contacts/gravatar.d.ts +14 -3
  317. package/dist/lib/contacts/gravatar.js +42 -5
  318. package/dist/lib/contacts/preparePhoto.d.ts +24 -0
  319. package/dist/lib/contacts/preparePhoto.js +250 -0
  320. package/dist/lib/contacts/useContactPhotoSrc.d.ts +19 -0
  321. package/dist/lib/contacts/useContactPhotoSrc.js +153 -0
  322. package/dist/lib/contacts/vcard.d.ts +3 -0
  323. package/dist/lib/contacts/vcard.js +59 -7
  324. package/dist/lib/crypto/escrowKeys.d.ts +8 -0
  325. package/dist/lib/crypto/escrowKeys.js +20 -1
  326. package/dist/lib/crypto/messageSecurity.d.ts +7 -4
  327. package/dist/lib/crypto/messageSecurity.js +23 -5
  328. package/dist/lib/crypto/passwordUnlock.d.ts +6 -1
  329. package/dist/lib/crypto/passwordUnlock.js +13 -2
  330. package/dist/lib/crypto/smime.js +12 -2
  331. package/dist/lib/mail/compose/composeQuoting.js +3 -2
  332. package/dist/lib/mail/compose/quotedImages.d.ts +6 -3
  333. package/dist/lib/mail/compose/quotedImages.js +35 -9
  334. package/dist/lib/mail/labelsApi.js +2 -2
  335. package/dist/lib/mail/mailApi.d.ts +8 -5
  336. package/dist/lib/mail/mailApi.js +73 -39
  337. package/dist/lib/mail/mailDetailHooks.js +11 -3
  338. package/dist/lib/mail/mailFilterRulesApi.js +2 -2
  339. package/dist/lib/mail/mailSignaturesApi.js +2 -2
  340. package/dist/lib/mail/mailboxImportApi.d.ts +1 -1
  341. package/dist/lib/mail/mailboxImportApi.js +3 -15
  342. package/dist/lib/mail/messageBodySanitizer.d.ts +6 -0
  343. package/dist/lib/mail/messageBodySanitizer.js +44 -1
  344. package/dist/lib/search/queryGrammar.js +12 -4
  345. package/dist/lib/search/searchTier3.d.ts +6 -1
  346. package/dist/lib/search/searchTier3.js +54 -25
  347. package/dist/lib/tasks/tasksApi.js +3 -3
  348. package/dist/lib/util/api.d.ts +26 -4
  349. package/dist/lib/util/api.js +73 -16
  350. package/dist/lib/util/apiQuery.d.ts +11 -0
  351. package/dist/lib/util/apiQuery.js +11 -0
  352. package/dist/lib/util/settleWithLimit.d.ts +5 -0
  353. package/dist/lib/util/settleWithLimit.js +25 -0
  354. package/lib/admin/auditLogApi.ts +2 -2
  355. package/lib/admin/distributionListsApi.ts +2 -2
  356. package/lib/admin/domainsApi.ts +2 -2
  357. package/lib/admin/escrowAuditLogApi.ts +2 -2
  358. package/lib/admin/escrowScopesApi.ts +2 -2
  359. package/lib/admin/pluginsApi.ts +45 -3
  360. package/lib/admin/retentionPolicyApi.ts +4 -0
  361. package/lib/admin/transportRulesApi.ts +2 -2
  362. package/lib/appearance/preferencesApi.ts +3 -14
  363. package/lib/auth/session.ts +239 -39
  364. package/lib/branding/brandingApi.ts +9 -21
  365. package/lib/calendar/calendarApi.ts +3 -1
  366. package/lib/calendar/eventSearch.ts +46 -6
  367. package/lib/calendar/freeBusyApi.ts +14 -6
  368. package/lib/calendar/recurrence.ts +59 -8
  369. package/lib/calendar/useDayKey.ts +45 -0
  370. package/lib/components/avatar/ContactAvatar.tsx +46 -8
  371. package/lib/components/avatar/ContactPhotoAvatar.tsx +26 -0
  372. package/lib/components/forms/CameraCaptureModal.tsx +133 -0
  373. package/lib/components/forms/ImageEditBadge.tsx +121 -0
  374. package/lib/components/menus/MenuButton.tsx +408 -0
  375. package/lib/components/navigation/BottomTabBar.tsx +30 -8
  376. package/lib/components/overlays/PopoverPortal.tsx +3 -2
  377. package/lib/components/pickers/TimeZonePicker.tsx +17 -1
  378. package/lib/contacts/contactsApi.ts +18 -19
  379. package/lib/contacts/gravatar.ts +47 -5
  380. package/lib/contacts/preparePhoto.ts +273 -0
  381. package/lib/contacts/useContactPhotoSrc.ts +177 -0
  382. package/lib/contacts/vcard.ts +60 -7
  383. package/lib/crypto/escrowKeys.ts +21 -1
  384. package/lib/crypto/messageSecurity.ts +33 -9
  385. package/lib/crypto/passwordUnlock.ts +14 -2
  386. package/lib/crypto/smime.ts +13 -2
  387. package/lib/mail/compose/composeQuoting.ts +3 -2
  388. package/lib/mail/compose/quotedImages.ts +39 -9
  389. package/lib/mail/labelsApi.ts +2 -2
  390. package/lib/mail/mailApi.ts +96 -39
  391. package/lib/mail/mailDetailHooks.ts +11 -3
  392. package/lib/mail/mailFilterRulesApi.ts +2 -2
  393. package/lib/mail/mailSignaturesApi.ts +2 -2
  394. package/lib/mail/mailboxImportApi.ts +9 -15
  395. package/lib/mail/messageBodySanitizer.ts +47 -1
  396. package/lib/search/queryGrammar.ts +13 -4
  397. package/lib/search/searchTier3.ts +65 -32
  398. package/lib/tasks/tasksApi.ts +3 -3
  399. package/lib/util/api.ts +99 -16
  400. package/lib/util/apiQuery.ts +13 -0
  401. package/lib/util/settleWithLimit.ts +25 -0
  402. package/package.json +1 -1
@@ -3,11 +3,11 @@
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
5
  import React, { useEffect, useRef, useState } from "react";
6
- import { ApiRequestError } from "../../../../../lib/util/api.js";
7
6
  import { LeftoverMailbox, listLeftoverMailboxes } from "../../../../../lib/admin/leftoverMailboxApi.js";
8
- import Alert from "../../../../../lib/components/feedback/Alert.js";
7
+ import Alert from "../ActionAlert.js";
9
8
  import Button from "../../../../../lib/components/buttons/Button.js";
10
9
  import EraseLeftoverDataDialog from "./EraseLeftoverDataDialog.js";
10
+ import { actionErrorMessage } from "../elevation.js";
11
11
 
12
12
  /** How many deleted mailboxes one request asks for. */
13
13
  const PAGE_SIZE = 50;
@@ -54,7 +54,7 @@ export default function LeftoverMailboxesSection({ refreshIntervalMs = LEFTOVER_
54
54
  setError(null);
55
55
  } catch (err) {
56
56
  if (current === generation.current) {
57
- setError(err instanceof ApiRequestError ? err.message : "Could not check for deleted mailboxes with remaining data.");
57
+ setError(actionErrorMessage(err, "Could not check for deleted mailboxes with remaining data."));
58
58
  }
59
59
  }
60
60
  }
@@ -69,7 +69,7 @@ export default function LeftoverMailboxesSection({ refreshIntervalMs = LEFTOVER_
69
69
  setNext(page.next);
70
70
  } catch (err) {
71
71
  if (current === generation.current) {
72
- setError(err instanceof ApiRequestError ? err.message : "Could not load more deleted mailboxes.");
72
+ setError(actionErrorMessage(err, "Could not load more deleted mailboxes."));
73
73
  }
74
74
  } finally {
75
75
  setLoadingMore(false);
@@ -3,11 +3,11 @@
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
5
  import React, { FormEvent, useState } from "react";
6
- import { ApiRequestError } from "../../../../../lib/util/api.js";
7
6
  import { Mailbox, updateMailbox } from "../../../../../lib/mail/mailApi.js";
8
7
  import { useApiClient } from "../../../../../lib/util/apiClientContext.js";
9
- import Alert from "../../../../../lib/components/feedback/Alert.js";
8
+ import Alert from "../ActionAlert.js";
10
9
  import Button from "../../../../../lib/components/buttons/Button.js";
10
+ import { actionErrorMessage } from "../elevation.js";
11
11
 
12
12
  const INPUT_CLASS =
13
13
  "w-full text-sm py-2 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
@@ -65,7 +65,7 @@ export default function ResourceSettingsCard({ mailbox, onUpdate }: ResourceSett
65
65
  onUpdate(updated);
66
66
  setSaved(true);
67
67
  } catch (err) {
68
- setError(err instanceof ApiRequestError ? err.message : "Could not save resource settings.");
68
+ setError(actionErrorMessage(err, "Could not save resource settings."));
69
69
  } finally {
70
70
  setSaving(false);
71
71
  }
@@ -3,7 +3,6 @@
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
5
  import React, { useEffect, useState } from "react";
6
- import { ApiRequestError } from "../../../../../lib/util/api.js";
7
6
  import {
8
7
  listMailboxAccess,
9
8
  MailboxAccessMember,
@@ -11,10 +10,11 @@ import {
11
10
  removeMailboxAccess,
12
11
  setMailboxAccess,
13
12
  } from "../../../../../lib/mail/mailboxAccessApi.js";
14
- import Alert from "../../../../../lib/components/feedback/Alert.js";
13
+ import Alert from "../ActionAlert.js";
15
14
  import Button from "../../../../../lib/components/buttons/Button.js";
16
15
  import Modal from "../../../../../lib/components/overlays/Modal.js";
17
16
  import PrincipalPicker from "../../sharing/PrincipalPicker.js";
17
+ import { actionErrorMessage } from "../elevation.js";
18
18
 
19
19
  const ROLE_LABELS: Record<MailboxAccessRole, string> = { viewer: "Read only", manager: "Full access" };
20
20
 
@@ -54,7 +54,7 @@ export default function ShareAccessCard({ mailboxUid, ownerUserUid, currentUserU
54
54
  setError(null);
55
55
  listMailboxAccess(mailboxUid)
56
56
  .then(setMembers)
57
- .catch((err) => setError(err instanceof ApiRequestError ? err.message : "Could not load share settings."))
57
+ .catch((err) => setError(actionErrorMessage(err, "Could not load share settings.")))
58
58
  .finally(() => setLoading(false));
59
59
  }
60
60
 
@@ -67,7 +67,7 @@ export default function ShareAccessCard({ mailboxUid, ownerUserUid, currentUserU
67
67
  await setMailboxAccess(mailboxUid, userUid, "manager");
68
68
  reload();
69
69
  } catch (err) {
70
- setError(err instanceof ApiRequestError ? err.message : "Could not grant access.");
70
+ setError(actionErrorMessage(err, "Could not grant access."));
71
71
  } finally {
72
72
  setSaving(false);
73
73
  }
@@ -82,7 +82,7 @@ export default function ShareAccessCard({ mailboxUid, ownerUserUid, currentUserU
82
82
  try {
83
83
  await removeMailboxAccess(mailboxUid, stale.userOrRoleId);
84
84
  } catch (err) {
85
- failure = err instanceof ApiRequestError ? err.message : "Could not remove the old entry.";
85
+ failure = actionErrorMessage(err, "Could not remove the old entry.");
86
86
  }
87
87
  }
88
88
  reload();
@@ -102,7 +102,7 @@ export default function ShareAccessCard({ mailboxUid, ownerUserUid, currentUserU
102
102
  await removeMailboxAccess(mailboxUid, userOrRoleId);
103
103
  reload();
104
104
  } catch (err) {
105
- setError(err instanceof ApiRequestError ? err.message : "Could not revoke access.");
105
+ setError(actionErrorMessage(err, "Could not revoke access."));
106
106
  } finally {
107
107
  setSaving(false);
108
108
  }
@@ -3,7 +3,6 @@
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
5
  import React, { ChangeEvent, FormEvent, useRef, useState } from "react";
6
- import { ApiRequestError } from "../../../../../lib/util/api.js";
7
6
  import {
8
7
  Branding,
9
8
  deleteBrandingIcon,
@@ -14,9 +13,10 @@ import {
14
13
  uploadBrandingLogo,
15
14
  uploadBrandingStylesheet,
16
15
  } from "../../../../../lib/branding/brandingApi.js";
17
- import Alert from "../../../../../lib/components/feedback/Alert.js";
16
+ import Alert from "../ActionAlert.js";
18
17
  import Button from "../../../../../lib/components/buttons/Button.js";
19
18
  import CopyButton from "../../../../../lib/components/buttons/CopyButton.js";
19
+ import { actionErrorMessage } from "../elevation.js";
20
20
 
21
21
  const INPUT_CLASS =
22
22
  "w-full text-sm py-2 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
@@ -74,10 +74,21 @@ export default function BrandingForm({ branding, onChange, embedded = false }: B
74
74
  setIconUrlInput(updated.iconUrl ?? "");
75
75
  setStylesheetUrlInput(updated.stylesheetUrl ?? "");
76
76
  })
77
- .catch((err) => setError(err instanceof ApiRequestError ? err.message : "Could not update branding."))
77
+ .catch((err) => setError(actionErrorMessage(err, "Could not update branding.")))
78
78
  .finally(() => setAssetBusy(null));
79
79
  }
80
80
 
81
+ /** Sets a branding asset to an address the administrator typed. Every visitor's browser loads it - the anonymous booking pages too - so it must be an
82
+ * encrypted (`https:`) address or one on this server (a path), not `http:`, `data:` or `javascript:`. */
83
+ function runUrl(name: string, field: "logoUrl" | "iconUrl" | "stylesheetUrl", value: string) {
84
+ const address = value.trim();
85
+ if (address !== "" && !/^https:\/\/[^\s/]/i.test(address) && !/^\/(?![/\\])/.test(address)) {
86
+ setError("Use an https:// address, or a path on this server, or upload a file instead.");
87
+ return;
88
+ }
89
+ void runAsset(name, () => updateBranding({ [field]: address }));
90
+ }
91
+
81
92
  function handleLogoFileChange(e: ChangeEvent<HTMLInputElement>) {
82
93
  const file = e.target.files?.[0];
83
94
  if (!file) return;
@@ -125,7 +136,7 @@ export default function BrandingForm({ branding, onChange, embedded = false }: B
125
136
  onChange(updated);
126
137
  setSaved(true);
127
138
  } catch (err) {
128
- setError(err instanceof ApiRequestError ? err.message : "Could not save branding.");
139
+ setError(actionErrorMessage(err, "Could not save branding."));
129
140
  } finally {
130
141
  setSaving(false);
131
142
  }
@@ -208,7 +219,7 @@ export default function BrandingForm({ branding, onChange, embedded = false }: B
208
219
  className="!w-auto"
209
220
  disabled={assetBusy !== null || logoUrlInput === (branding.logoUrl ?? "")}
210
221
  loading={assetBusy === "logo-url"}
211
- onClick={() => void runAsset("logo-url", () => updateBranding({ logoUrl: logoUrlInput }))}
222
+ onClick={() => runUrl("logo-url", "logoUrl", logoUrlInput)}
212
223
  >
213
224
  Set
214
225
  </Button>
@@ -280,7 +291,7 @@ export default function BrandingForm({ branding, onChange, embedded = false }: B
280
291
  className="!w-auto"
281
292
  disabled={assetBusy !== null || iconUrlInput === (branding.iconUrl ?? "")}
282
293
  loading={assetBusy === "icon-url"}
283
- onClick={() => void runAsset("icon-url", () => updateBranding({ iconUrl: iconUrlInput }))}
294
+ onClick={() => runUrl("icon-url", "iconUrl", iconUrlInput)}
284
295
  >
285
296
  Set
286
297
  </Button>
@@ -331,6 +342,10 @@ export default function BrandingForm({ branding, onChange, embedded = false }: B
331
342
  </div>
332
343
  <label className="flex flex-col gap-1.5 text-sm">
333
344
  <span className="font-semibold">Or use an external stylesheet URL</span>
345
+ <span className="text-xs text-text-muted">
346
+ Every visitor&rsquo;s browser loads it, and a stylesheet can read what the page shows: only use an address you control, or
347
+ upload the file instead.
348
+ </span>
334
349
  <div className="flex gap-2">
335
350
  <input
336
351
  aria-label="Stylesheet URL"
@@ -344,9 +359,7 @@ export default function BrandingForm({ branding, onChange, embedded = false }: B
344
359
  className="!w-auto"
345
360
  disabled={assetBusy !== null || stylesheetUrlInput === (branding.stylesheetUrl ?? "")}
346
361
  loading={assetBusy === "stylesheet-url"}
347
- onClick={() =>
348
- void runAsset("stylesheet-url", () => updateBranding({ stylesheetUrl: stylesheetUrlInput }))
349
- }
362
+ onClick={() => runUrl("stylesheet-url", "stylesheetUrl", stylesheetUrlInput)}
350
363
  >
351
364
  Set
352
365
  </Button>
@@ -3,11 +3,11 @@
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
5
  import React, { useEffect, useState } from "react";
6
- import { ApiRequestError } from "../../../../../lib/util/api.js";
7
6
  import { DnsRecordCheck, Domain, getDnsSetup, getDomain, verifyDomain } from "../../../../../lib/admin/domainsApi.js";
8
- import Alert from "../../../../../lib/components/feedback/Alert.js";
7
+ import Alert from "../ActionAlert.js";
9
8
  import Button from "../../../../../lib/components/buttons/Button.js";
10
9
  import CopyButton from "../../../../../lib/components/buttons/CopyButton.js";
10
+ import { actionErrorMessage } from "../elevation.js";
11
11
 
12
12
  const RECORD_TYPE_LABELS: Record<DnsRecordCheck["type"], string> = {
13
13
  ownership: "Ownership (TXT)",
@@ -88,7 +88,7 @@ export default function DomainDnsSetup({ uid, onLoaded }: DomainDnsSetupProps) {
88
88
  setDnsSetup(checks);
89
89
  onLoaded?.(d);
90
90
  })
91
- .catch((err) => setError(err instanceof ApiRequestError ? err.message : "Could not load this domain."))
91
+ .catch((err) => setError(actionErrorMessage(err, "Could not load this domain.")))
92
92
  .finally(() => setLoading(false));
93
93
  }
94
94
 
@@ -109,7 +109,7 @@ export default function DomainDnsSetup({ uid, onLoaded }: DomainDnsSetupProps) {
109
109
  setDnsSetup(checks);
110
110
  onLoaded?.(d);
111
111
  } catch (err) {
112
- setVerifyError(err instanceof ApiRequestError ? err.message : "Could not verify this domain.");
112
+ setVerifyError(actionErrorMessage(err, "Could not verify this domain."));
113
113
  } finally {
114
114
  setVerifying(false);
115
115
  }
@@ -3,10 +3,11 @@
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
5
  import React, { FormEvent, useEffect, useState } from "react";
6
- import { ApiRequestError } from "../../../../../lib/util/api.js";
7
6
  import { EncryptionPolicy, PolicyState, updateEncryptionPolicy } from "../../../../../lib/crypto/keyvaultApi.js";
8
- import Alert from "../../../../../lib/components/feedback/Alert.js";
7
+ import Alert from "../ActionAlert.js";
9
8
  import Button from "../../../../../lib/components/buttons/Button.js";
9
+ import Modal from "../../../../../lib/components/overlays/Modal.js";
10
+ import { actionErrorMessage } from "../elevation.js";
10
11
 
11
12
  const SELECT_CLASS =
12
13
  "w-full text-sm py-2 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
@@ -54,8 +55,21 @@ export default function EncryptionPolicyForm({ policy, onChange, onDirtyChange,
54
55
  const dirty: boolean = TIERS.some((tier) => values[tier.key] !== savedValues[tier.key]);
55
56
  useEffect(() => onDirtyChange?.(dirty), [dirty]);
56
57
 
57
- async function handleSubmit(e: FormEvent) {
58
+ // Tiers this save would newly set to "Never encrypt", which switches encryption off for everyone's mail of that kind: confirmed first.
59
+ const [confirmingProhibit, setConfirmingProhibit] = useState<string[] | null>(null);
60
+
61
+ function handleSubmit(e: FormEvent) {
58
62
  e.preventDefault();
63
+ const newlyProhibited = TIERS.filter((tier) => values[tier.key] === "prohibited" && savedValues[tier.key] !== "prohibited");
64
+ if (newlyProhibited.length > 0) {
65
+ setConfirmingProhibit(newlyProhibited.map((tier) => tier.label));
66
+ return;
67
+ }
68
+ void save();
69
+ }
70
+
71
+ async function save() {
72
+ setConfirmingProhibit(null);
59
73
  setError(null);
60
74
  setSaved(false);
61
75
  setSaving(true);
@@ -65,7 +79,7 @@ export default function EncryptionPolicyForm({ policy, onChange, onDirtyChange,
65
79
  setSavedValues(values);
66
80
  setSaved(true);
67
81
  } catch (err) {
68
- setError(err instanceof ApiRequestError ? err.message : "Could not save the encryption policy.");
82
+ setError(actionErrorMessage(err, "Could not save the encryption policy."));
69
83
  } finally {
70
84
  setSaving(false);
71
85
  }
@@ -114,6 +128,21 @@ export default function EncryptionPolicyForm({ policy, onChange, onDirtyChange,
114
128
  </Button>
115
129
  </div>
116
130
  </form>
131
+
132
+ <Modal open={confirmingProhibit !== null} onClose={() => setConfirmingProhibit(null)} title="Turn off encryption?">
133
+ <p className="text-sm mb-3">
134
+ Saving sets <strong>{confirmingProhibit?.join(", ")}</strong> to Never encrypt. Nobody on this server can then encrypt
135
+ that mail end to end, whatever they have chosen for themselves, until an administrator allows it again.
136
+ </p>
137
+ <div className="flex gap-3 justify-end">
138
+ <Button type="button" variant="secondary" className="!w-auto" onClick={() => setConfirmingProhibit(null)}>
139
+ Cancel
140
+ </Button>
141
+ <Button type="button" className="!w-auto !bg-none !bg-danger !border-danger hover:!bg-danger" onClick={() => void save()}>
142
+ Save and turn off encryption
143
+ </Button>
144
+ </div>
145
+ </Modal>
117
146
  </div>
118
147
  );
119
148
  }
@@ -3,8 +3,8 @@
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
5
  import React, { ReactNode, useEffect, useState } from "react";
6
- import { ApiRequestError } from "../../../../../lib/util/api.js";
7
- import Alert from "../../../../../lib/components/feedback/Alert.js";
6
+ import { actionErrorMessage } from "../elevation.js";
7
+ import Alert from "../ActionAlert.js";
8
8
 
9
9
  export interface LoadedSettingsFormProps<T> {
10
10
  load: () => Promise<T>;
@@ -21,7 +21,7 @@ export default function LoadedSettingsForm<T>({ load, loadErrorMessage, children
21
21
  useEffect(() => {
22
22
  load()
23
23
  .then(setValue)
24
- .catch((err) => setError(err instanceof ApiRequestError ? err.message : loadErrorMessage));
24
+ .catch((err) => setError(actionErrorMessage(err, loadErrorMessage)));
25
25
  }, []);
26
26
 
27
27
  if (error) {
@@ -3,17 +3,17 @@
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
5
  import React, { FormEvent, useEffect, useRef, useState } from "react";
6
- import { ApiRequestError } from "../../../../../lib/util/api.js";
7
6
  import { getMailboxPolicy } from "../../../../../lib/admin/mailboxPolicyApi.js";
8
7
  import { LeftoverConflict, leftoverConflictOf } from "../../../../../lib/admin/leftoverMailboxApi.js";
9
8
  import { createMailbox, listMailboxDomains, Mailbox, resolveMailboxOwner, ResolvedPrincipal } from "../../../../../lib/mail/mailApi.js";
10
9
  import { describeTimeZone, deviceTimeZone, zoneClock } from "../../../../../lib/util/timeZone.js";
11
10
  import { useApiClient } from "../../../../../lib/util/apiClientContext.js";
12
- import Alert from "../../../../../lib/components/feedback/Alert.js";
11
+ import Alert from "../ActionAlert.js";
13
12
  import Button from "../../../../../lib/components/buttons/Button.js";
14
13
  import FormField from "../../../../../lib/components/forms/FormField.js";
15
14
  import PrincipalResolver, { describePerson } from "../../sharing/PrincipalResolver.js";
16
15
  import EraseLeftoverDataDialog from "../mailboxes/EraseLeftoverDataDialog.js";
16
+ import { actionErrorMessage } from "../elevation.js";
17
17
 
18
18
  const INPUT_CLASS =
19
19
  "w-full text-sm py-2.5 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
@@ -98,6 +98,11 @@ export default function MailboxCreateForm({ onCreated, defaults, submitLabel = "
98
98
  setError("A primary SMTP address is required.");
99
99
  return;
100
100
  }
101
+ // With the domain chosen beside it, a local part with an "@" would make `a@b.com@domain`, which the server refuses without saying why.
102
+ if (constrained && /[@@﹫]/.test(localPart)) {
103
+ setError("The part before the domain can't contain \"@\" - choose the domain from the list instead.");
104
+ return;
105
+ }
101
106
  if (!displayName.trim()) {
102
107
  setError("A display name is required.");
103
108
  return;
@@ -143,7 +148,7 @@ export default function MailboxCreateForm({ onCreated, defaults, submitLabel = "
143
148
  // Not a plain failure: the address is taken by what a deleted mailbox left, which can be erased right here.
144
149
  setLeftover({ address, conflict });
145
150
  } else {
146
- setError(err instanceof ApiRequestError ? err.message : "Could not create the mailbox.");
151
+ setError(actionErrorMessage(err, "Could not create the mailbox."));
147
152
  }
148
153
  } finally {
149
154
  setSaving(false);
@@ -3,10 +3,10 @@
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
5
  import React, { FormEvent, useEffect, useState } from "react";
6
- import { ApiRequestError } from "../../../../../lib/util/api.js";
7
6
  import { MailboxPolicy, updateMailboxPolicy } from "../../../../../lib/admin/mailboxPolicyApi.js";
8
- import Alert from "../../../../../lib/components/feedback/Alert.js";
7
+ import Alert from "../ActionAlert.js";
9
8
  import Button from "../../../../../lib/components/buttons/Button.js";
9
+ import { actionErrorMessage } from "../elevation.js";
10
10
 
11
11
  const INPUT_CLASS =
12
12
  "w-full text-sm py-2 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
@@ -109,7 +109,7 @@ export default function MailboxPolicyForm({ policy, onChange, onDirtyChange, emb
109
109
  setBaseline(current);
110
110
  setSaved(true);
111
111
  } catch (err) {
112
- setError(err instanceof ApiRequestError ? err.message : "Could not save the mailbox policy.");
112
+ setError(actionErrorMessage(err, "Could not save the mailbox policy."));
113
113
  } finally {
114
114
  setSaving(false);
115
115
  }