@rapidmx/web-client 0.10.0 → 0.11.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 (310) hide show
  1. package/README.md +183 -2
  2. package/apps/admin/_layout.tsx +8 -2
  3. package/apps/admin/index.tsx +7 -1
  4. package/apps/admin/ingest-queue/index.tsx +2 -1
  5. package/apps/admin/mailboxes/[uid].tsx +23 -10
  6. package/apps/admin/quarantine/index.tsx +2 -1
  7. package/apps/admin/signing-certificates/index.tsx +343 -0
  8. package/apps/escrow/_layout.tsx +8 -2
  9. package/apps/shared/appearance/AppearanceForm.tsx +392 -0
  10. package/apps/shared/appearance/AppearanceHead.tsx +49 -0
  11. package/apps/shared/appearance/AppearanceProvider.tsx +470 -0
  12. package/apps/shared/appearance/ColorField.tsx +107 -0
  13. package/apps/shared/appearance/appearanceCache.ts +106 -0
  14. package/apps/shared/appearance/appearanceContext.ts +77 -0
  15. package/apps/shared/appearance/bootScript.ts +35 -0
  16. package/apps/shared/appearance/color.ts +169 -0
  17. package/apps/shared/appearance/photo.ts +88 -0
  18. package/apps/shared/appearance/resolvedTheme.ts +67 -0
  19. package/apps/shared/appearance/theme.ts +355 -0
  20. package/apps/shared/components/admin/layout/AdminShell.tsx +22 -10
  21. package/apps/shared/components/admin/mailboxes/ShareAccessCard.tsx +107 -60
  22. package/apps/shared/components/admin/settings/BrandingForm.tsx +24 -0
  23. package/apps/shared/components/admin/settings/PluginsManager.tsx +228 -25
  24. package/apps/shared/components/admin/setup/SetupWizard.tsx +2 -1
  25. package/apps/shared/components/calendar/CalendarListSidebar.tsx +4 -5
  26. package/apps/shared/components/contacts/ContactForm.tsx +11 -5
  27. package/apps/shared/components/contacts/ContactsSidebar.tsx +5 -3
  28. package/apps/shared/components/contacts/ContactsToolbar.tsx +25 -52
  29. package/apps/shared/components/contacts/layout/ContactsShell.tsx +10 -5
  30. package/apps/shared/components/escrow/layout/EscrowShell.tsx +13 -6
  31. package/apps/shared/components/layout/AppShell.tsx +98 -32
  32. package/apps/shared/components/layout/BrandingChrome.tsx +200 -13
  33. package/apps/shared/components/layout/RailIcon.tsx +100 -0
  34. package/apps/shared/components/layout/ResponsiveToolbar.tsx +315 -0
  35. package/apps/shared/components/layout/ThemeSwitch.tsx +84 -0
  36. package/apps/shared/components/layout/UserMenu.tsx +75 -6
  37. package/apps/shared/components/mail/ConversationList.tsx +4 -2
  38. package/apps/shared/components/mail/ConversationThreadPane.tsx +487 -475
  39. package/apps/shared/components/mail/LazyReadingPane.tsx +14 -16
  40. package/apps/shared/components/mail/MailSelectionBar.tsx +2 -10
  41. package/apps/shared/components/mail/MessageDetailPane.tsx +366 -287
  42. package/apps/shared/components/mail/OutboxBadge.tsx +44 -0
  43. package/apps/shared/components/mail/OutboxRowStatus.tsx +31 -0
  44. package/apps/shared/components/mail/compose/ComposeContext.tsx +35 -2
  45. package/apps/shared/components/mail/compose/ComposeWindow.tsx +239 -437
  46. package/apps/shared/components/mail/compose/encryptionRequirement.ts +86 -0
  47. package/apps/shared/components/mail/layout/MailShell.tsx +39 -25
  48. package/apps/shared/components/mail/reading/EncryptedBody.tsx +65 -0
  49. package/apps/shared/components/mail/reading/EncryptedPreview.tsx +35 -0
  50. package/apps/shared/components/mail/reading/MessageBody.tsx +240 -0
  51. package/apps/shared/components/mail/reading/MessageCard.tsx +174 -0
  52. package/apps/shared/components/mail/reading/bodyContent.ts +100 -0
  53. package/apps/shared/components/mail/reading/bodyHtml.ts +298 -0
  54. package/apps/shared/components/mail/reading/color.ts +245 -0
  55. package/apps/shared/components/mail/reading/frameControl.ts +142 -0
  56. package/apps/shared/components/mail/reading/frameDocument.ts +123 -0
  57. package/apps/shared/components/mail/reading/safeDocument.ts +24 -0
  58. package/apps/shared/components/mail/reading/themeAdaptation.ts +221 -0
  59. package/apps/shared/components/mail/reading/themeSurface.ts +90 -0
  60. package/apps/shared/components/mail/reading/viewOriginal.ts +38 -0
  61. package/apps/shared/components/settings/SigningCertificateCard.tsx +344 -0
  62. package/apps/shared/components/settings/layout/SettingsShell.tsx +1 -0
  63. package/apps/shared/components/sharing/PrincipalPicker.tsx +145 -0
  64. package/apps/shared/components/tasks/TasksSidebar.tsx +5 -3
  65. package/apps/shared/components/tasks/layout/TasksShell.tsx +9 -5
  66. package/apps/shared/mail/folderCounts.ts +9 -3
  67. package/apps/shared/mail/folderTree.ts +143 -0
  68. package/apps/shared/mail/outbox/UnlockBridge.tsx +23 -0
  69. package/apps/shared/mail/outbox/composeBridge.ts +69 -0
  70. package/apps/shared/mail/outbox/outboxState.ts +88 -0
  71. package/apps/shared/mail/outbox/pendingSends.ts +146 -0
  72. package/apps/shared/mail/outbox/sendDecision.ts +157 -0
  73. package/apps/shared/mail/outbox/sendJob.ts +427 -0
  74. package/apps/shared/mail/outbox/sendOutcomes.ts +146 -0
  75. package/apps/shared/mail/outbox/sendState.ts +35 -0
  76. package/apps/shared/mail/outbox/useOutboxStatus.ts +61 -0
  77. package/apps/shared/mail/useMailConnection.ts +81 -28
  78. package/apps/shared/mail/useMailLiveUpdates.ts +55 -10
  79. package/apps/shared/mail/useNewMailNotifications.ts +47 -32
  80. package/apps/shared/navigation/AppRouter.tsx +2 -2
  81. package/apps/shared/notifications/NotificationCenter.tsx +215 -0
  82. package/apps/shared/notifications/NotificationHistoryDialog.tsx +90 -0
  83. package/apps/shared/notifications/apiErrors.ts +98 -0
  84. package/apps/shared/notifications/headerOffset.ts +35 -0
  85. package/apps/shared/notifications/pushStatus.ts +56 -0
  86. package/apps/shared/notifications/store.ts +549 -0
  87. package/apps/shared/notifications/systemErrors.ts +63 -0
  88. package/apps/shared/notifications/useNotifications.ts +41 -0
  89. package/apps/shared/signing/enrollmentStorage.ts +33 -0
  90. package/apps/shared/signing/enrollmentTracker.ts +385 -0
  91. package/apps/shared/signing/enrollmentView.ts +251 -0
  92. package/apps/shared/signing/signingInfo.ts +58 -0
  93. package/apps/shared/signing/useNow.ts +19 -0
  94. package/apps/shared/signing/useSigningEnrollmentWatcher.ts +90 -0
  95. package/apps/shared/styles/app.css +80 -0
  96. package/apps/www/_layout.tsx +8 -2
  97. package/apps/www/_routes.ts +1 -0
  98. package/apps/www/calendar/index.tsx +9 -14
  99. package/apps/www/contacts/[uid].tsx +5 -8
  100. package/apps/www/contacts/index.tsx +587 -584
  101. package/apps/www/index.tsx +38 -27
  102. package/apps/www/messages/[uid].tsx +3 -1
  103. package/apps/www/settings/appearance/index.tsx +21 -0
  104. package/apps/www/settings/auto-reply/index.tsx +3 -7
  105. package/apps/www/settings/encryption/index.tsx +151 -116
  106. package/apps/www/settings/filters/[uid].tsx +3 -1
  107. package/apps/www/settings/filters/new/index.tsx +3 -1
  108. package/apps/www/settings/privacy/index.tsx +3 -8
  109. package/apps/www/settings/read-receipts/index.tsx +3 -7
  110. package/apps/www/settings/sharing/index.tsx +44 -65
  111. package/apps/www/settings/signatures/[uid].tsx +3 -1
  112. package/apps/www/settings/signatures/new/index.tsx +3 -2
  113. package/apps/www/tasks/index.tsx +11 -16
  114. package/dist/apps/admin/_layout.d.ts +5 -1
  115. package/dist/apps/admin/_layout.js +3 -2
  116. package/dist/apps/admin/index.js +3 -2
  117. package/dist/apps/admin/ingest-queue/index.js +2 -1
  118. package/dist/apps/admin/mailboxes/[uid].js +9 -6
  119. package/dist/apps/admin/quarantine/index.js +2 -1
  120. package/dist/apps/admin/signing-certificates/index.d.ts +3 -0
  121. package/dist/apps/admin/signing-certificates/index.js +161 -0
  122. package/dist/apps/escrow/_layout.d.ts +5 -1
  123. package/dist/apps/escrow/_layout.js +3 -2
  124. package/dist/apps/shared/appearance/AppearanceForm.d.ts +7 -0
  125. package/dist/apps/shared/appearance/AppearanceForm.js +131 -0
  126. package/dist/apps/shared/appearance/AppearanceHead.d.ts +15 -0
  127. package/dist/apps/shared/appearance/AppearanceHead.js +31 -0
  128. package/dist/apps/shared/appearance/AppearanceProvider.d.ts +32 -0
  129. package/dist/apps/shared/appearance/AppearanceProvider.js +390 -0
  130. package/dist/apps/shared/appearance/ColorField.d.ts +22 -0
  131. package/dist/apps/shared/appearance/ColorField.js +40 -0
  132. package/dist/apps/shared/appearance/appearanceCache.d.ts +45 -0
  133. package/dist/apps/shared/appearance/appearanceCache.js +80 -0
  134. package/dist/apps/shared/appearance/appearanceContext.d.ts +45 -0
  135. package/dist/apps/shared/appearance/appearanceContext.js +29 -0
  136. package/dist/apps/shared/appearance/bootScript.d.ts +16 -0
  137. package/dist/apps/shared/appearance/bootScript.js +33 -0
  138. package/dist/apps/shared/appearance/color.d.ts +65 -0
  139. package/dist/apps/shared/appearance/color.js +132 -0
  140. package/dist/apps/shared/appearance/photo.d.ts +17 -0
  141. package/dist/apps/shared/appearance/photo.js +79 -0
  142. package/dist/apps/shared/appearance/resolvedTheme.d.ts +21 -0
  143. package/dist/apps/shared/appearance/resolvedTheme.js +55 -0
  144. package/dist/apps/shared/appearance/theme.d.ts +111 -0
  145. package/dist/apps/shared/appearance/theme.js +251 -0
  146. package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +1 -1
  147. package/dist/apps/shared/components/admin/layout/AdminShell.js +16 -6
  148. package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.d.ts +10 -5
  149. package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +49 -34
  150. package/dist/apps/shared/components/admin/settings/BrandingForm.d.ts +2 -0
  151. package/dist/apps/shared/components/admin/settings/BrandingForm.js +7 -1
  152. package/dist/apps/shared/components/admin/settings/PluginsManager.js +106 -20
  153. package/dist/apps/shared/components/admin/setup/SetupWizard.js +2 -1
  154. package/dist/apps/shared/components/calendar/CalendarListSidebar.js +8 -8
  155. package/dist/apps/shared/components/contacts/ContactForm.js +1 -1
  156. package/dist/apps/shared/components/contacts/ContactsSidebar.js +4 -2
  157. package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +3 -1
  158. package/dist/apps/shared/components/contacts/ContactsToolbar.js +24 -9
  159. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +4 -1
  160. package/dist/apps/shared/components/escrow/layout/EscrowShell.js +7 -4
  161. package/dist/apps/shared/components/layout/AppShell.d.ts +6 -1
  162. package/dist/apps/shared/components/layout/AppShell.js +59 -13
  163. package/dist/apps/shared/components/layout/BrandingChrome.d.ts +69 -10
  164. package/dist/apps/shared/components/layout/BrandingChrome.js +140 -12
  165. package/dist/apps/shared/components/layout/RailIcon.d.ts +21 -0
  166. package/dist/apps/shared/components/layout/RailIcon.js +85 -0
  167. package/dist/apps/shared/components/layout/ResponsiveToolbar.d.ts +55 -0
  168. package/dist/apps/shared/components/layout/ResponsiveToolbar.js +199 -0
  169. package/dist/apps/shared/components/layout/ThemeSwitch.d.ts +9 -0
  170. package/dist/apps/shared/components/layout/ThemeSwitch.js +54 -0
  171. package/dist/apps/shared/components/layout/UserMenu.d.ts +7 -1
  172. package/dist/apps/shared/components/layout/UserMenu.js +41 -7
  173. package/dist/apps/shared/components/mail/ConversationList.js +3 -2
  174. package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +2 -1
  175. package/dist/apps/shared/components/mail/ConversationThreadPane.js +42 -20
  176. package/dist/apps/shared/components/mail/LazyReadingPane.js +9 -8
  177. package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +3 -4
  178. package/dist/apps/shared/components/mail/MailSelectionBar.js +2 -3
  179. package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +18 -7
  180. package/dist/apps/shared/components/mail/MessageDetailPane.js +86 -41
  181. package/dist/apps/shared/components/mail/OutboxBadge.d.ts +17 -0
  182. package/dist/apps/shared/components/mail/OutboxBadge.js +18 -0
  183. package/dist/apps/shared/components/mail/OutboxRowStatus.d.ts +10 -0
  184. package/dist/apps/shared/components/mail/OutboxRowStatus.js +19 -0
  185. package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +8 -0
  186. package/dist/apps/shared/components/mail/compose/ComposeContext.js +28 -3
  187. package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +2 -1
  188. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +229 -328
  189. package/dist/apps/shared/components/mail/compose/encryptionRequirement.d.ts +49 -0
  190. package/dist/apps/shared/components/mail/compose/encryptionRequirement.js +35 -0
  191. package/dist/apps/shared/components/mail/layout/MailShell.d.ts +2 -0
  192. package/dist/apps/shared/components/mail/layout/MailShell.js +20 -14
  193. package/dist/apps/shared/components/mail/reading/EncryptedBody.d.ts +21 -0
  194. package/dist/apps/shared/components/mail/reading/EncryptedBody.js +22 -0
  195. package/dist/apps/shared/components/mail/reading/EncryptedPreview.d.ts +18 -0
  196. package/dist/apps/shared/components/mail/reading/EncryptedPreview.js +22 -0
  197. package/dist/apps/shared/components/mail/reading/MessageBody.d.ts +32 -0
  198. package/dist/apps/shared/components/mail/reading/MessageBody.js +136 -0
  199. package/dist/apps/shared/components/mail/reading/MessageCard.d.ts +62 -0
  200. package/dist/apps/shared/components/mail/reading/MessageCard.js +58 -0
  201. package/dist/apps/shared/components/mail/reading/bodyContent.d.ts +38 -0
  202. package/dist/apps/shared/components/mail/reading/bodyContent.js +84 -0
  203. package/dist/apps/shared/components/mail/reading/bodyHtml.d.ts +47 -0
  204. package/dist/apps/shared/components/mail/reading/bodyHtml.js +267 -0
  205. package/dist/apps/shared/components/mail/reading/color.d.ts +63 -0
  206. package/dist/apps/shared/components/mail/reading/color.js +201 -0
  207. package/dist/apps/shared/components/mail/reading/frameControl.d.ts +33 -0
  208. package/dist/apps/shared/components/mail/reading/frameControl.js +120 -0
  209. package/dist/apps/shared/components/mail/reading/frameDocument.d.ts +52 -0
  210. package/dist/apps/shared/components/mail/reading/frameDocument.js +98 -0
  211. package/dist/apps/shared/components/mail/reading/safeDocument.d.ts +3 -0
  212. package/dist/apps/shared/components/mail/reading/safeDocument.js +12 -0
  213. package/dist/apps/shared/components/mail/reading/themeAdaptation.d.ts +56 -0
  214. package/dist/apps/shared/components/mail/reading/themeAdaptation.js +144 -0
  215. package/dist/apps/shared/components/mail/reading/themeSurface.d.ts +17 -0
  216. package/dist/apps/shared/components/mail/reading/themeSurface.js +83 -0
  217. package/dist/apps/shared/components/mail/reading/viewOriginal.d.ts +9 -0
  218. package/dist/apps/shared/components/mail/reading/viewOriginal.js +32 -0
  219. package/dist/apps/shared/components/settings/SigningCertificateCard.d.ts +32 -0
  220. package/dist/apps/shared/components/settings/SigningCertificateCard.js +98 -0
  221. package/dist/apps/shared/components/settings/layout/SettingsShell.js +1 -0
  222. package/dist/apps/shared/components/sharing/PrincipalPicker.d.ts +26 -0
  223. package/dist/apps/shared/components/sharing/PrincipalPicker.js +77 -0
  224. package/dist/apps/shared/components/tasks/TasksSidebar.js +4 -2
  225. package/dist/apps/shared/components/tasks/layout/TasksShell.js +3 -1
  226. package/dist/apps/shared/mail/folderCounts.d.ts +1 -1
  227. package/dist/apps/shared/mail/folderCounts.js +9 -3
  228. package/dist/apps/shared/mail/folderTree.d.ts +55 -0
  229. package/dist/apps/shared/mail/folderTree.js +116 -0
  230. package/dist/apps/shared/mail/outbox/UnlockBridge.d.ts +5 -0
  231. package/dist/apps/shared/mail/outbox/UnlockBridge.js +18 -0
  232. package/dist/apps/shared/mail/outbox/composeBridge.d.ts +34 -0
  233. package/dist/apps/shared/mail/outbox/composeBridge.js +32 -0
  234. package/dist/apps/shared/mail/outbox/outboxState.d.ts +41 -0
  235. package/dist/apps/shared/mail/outbox/outboxState.js +42 -0
  236. package/dist/apps/shared/mail/outbox/pendingSends.d.ts +39 -0
  237. package/dist/apps/shared/mail/outbox/pendingSends.js +109 -0
  238. package/dist/apps/shared/mail/outbox/sendDecision.d.ts +80 -0
  239. package/dist/apps/shared/mail/outbox/sendDecision.js +94 -0
  240. package/dist/apps/shared/mail/outbox/sendJob.d.ts +68 -0
  241. package/dist/apps/shared/mail/outbox/sendJob.js +319 -0
  242. package/dist/apps/shared/mail/outbox/sendOutcomes.d.ts +3 -0
  243. package/dist/apps/shared/mail/outbox/sendOutcomes.js +141 -0
  244. package/dist/apps/shared/mail/outbox/sendState.d.ts +25 -0
  245. package/dist/apps/shared/mail/outbox/sendState.js +8 -0
  246. package/dist/apps/shared/mail/outbox/useOutboxStatus.d.ts +11 -0
  247. package/dist/apps/shared/mail/outbox/useOutboxStatus.js +49 -0
  248. package/dist/apps/shared/mail/useMailConnection.d.ts +9 -8
  249. package/dist/apps/shared/mail/useMailConnection.js +64 -22
  250. package/dist/apps/shared/mail/useMailLiveUpdates.d.ts +17 -4
  251. package/dist/apps/shared/mail/useMailLiveUpdates.js +36 -10
  252. package/dist/apps/shared/mail/useNewMailNotifications.d.ts +4 -10
  253. package/dist/apps/shared/mail/useNewMailNotifications.js +43 -23
  254. package/dist/apps/shared/navigation/AppRouter.js +2 -2
  255. package/dist/apps/shared/notifications/NotificationCenter.d.ts +19 -0
  256. package/dist/apps/shared/notifications/NotificationCenter.js +90 -0
  257. package/dist/apps/shared/notifications/NotificationHistoryDialog.d.ts +10 -0
  258. package/dist/apps/shared/notifications/NotificationHistoryDialog.js +36 -0
  259. package/dist/apps/shared/notifications/apiErrors.d.ts +19 -0
  260. package/dist/apps/shared/notifications/apiErrors.js +86 -0
  261. package/dist/apps/shared/notifications/headerOffset.d.ts +8 -0
  262. package/dist/apps/shared/notifications/headerOffset.js +33 -0
  263. package/dist/apps/shared/notifications/pushStatus.d.ts +9 -0
  264. package/dist/apps/shared/notifications/pushStatus.js +54 -0
  265. package/dist/apps/shared/notifications/store.d.ts +136 -0
  266. package/dist/apps/shared/notifications/store.js +416 -0
  267. package/dist/apps/shared/notifications/systemErrors.d.ts +9 -0
  268. package/dist/apps/shared/notifications/systemErrors.js +58 -0
  269. package/dist/apps/shared/notifications/useNotifications.d.ts +17 -0
  270. package/dist/apps/shared/notifications/useNotifications.js +18 -0
  271. package/dist/apps/shared/signing/enrollmentStorage.d.ts +10 -0
  272. package/dist/apps/shared/signing/enrollmentStorage.js +33 -0
  273. package/dist/apps/shared/signing/enrollmentTracker.d.ts +73 -0
  274. package/dist/apps/shared/signing/enrollmentTracker.js +307 -0
  275. package/dist/apps/shared/signing/enrollmentView.d.ts +57 -0
  276. package/dist/apps/shared/signing/enrollmentView.js +214 -0
  277. package/dist/apps/shared/signing/signingInfo.d.ts +11 -0
  278. package/dist/apps/shared/signing/signingInfo.js +48 -0
  279. package/dist/apps/shared/signing/useNow.d.ts +2 -0
  280. package/dist/apps/shared/signing/useNow.js +18 -0
  281. package/dist/apps/shared/signing/useSigningEnrollmentWatcher.d.ts +16 -0
  282. package/dist/apps/shared/signing/useSigningEnrollmentWatcher.js +87 -0
  283. package/dist/apps/shared/styles/app.css +80 -0
  284. package/dist/apps/www/_layout.d.ts +5 -1
  285. package/dist/apps/www/_layout.js +3 -2
  286. package/dist/apps/www/_routes.js +1 -0
  287. package/dist/apps/www/calendar/index.js +3 -4
  288. package/dist/apps/www/contacts/[uid].js +5 -7
  289. package/dist/apps/www/contacts/index.js +14 -21
  290. package/dist/apps/www/index.js +37 -19
  291. package/dist/apps/www/messages/[uid].js +3 -1
  292. package/dist/apps/www/settings/appearance/index.d.ts +4 -0
  293. package/dist/apps/www/settings/appearance/index.js +13 -0
  294. package/dist/apps/www/settings/auto-reply/index.js +3 -6
  295. package/dist/apps/www/settings/encryption/index.js +103 -95
  296. package/dist/apps/www/settings/filters/[uid].js +3 -1
  297. package/dist/apps/www/settings/filters/new/index.js +3 -1
  298. package/dist/apps/www/settings/privacy/index.js +5 -8
  299. package/dist/apps/www/settings/read-receipts/index.js +3 -6
  300. package/dist/apps/www/settings/sharing/index.js +19 -33
  301. package/dist/apps/www/settings/signatures/[uid].js +3 -1
  302. package/dist/apps/www/settings/signatures/new/index.js +3 -2
  303. package/dist/apps/www/tasks/index.js +8 -14
  304. package/package.json +2 -2
  305. package/apps/shared/components/mail/NewMailToasts.tsx +0 -141
  306. package/apps/shared/components/mail/compose/SendFailureAlert.tsx +0 -48
  307. package/dist/apps/shared/components/mail/NewMailToasts.d.ts +0 -19
  308. package/dist/apps/shared/components/mail/NewMailToasts.js +0 -55
  309. package/dist/apps/shared/components/mail/compose/SendFailureAlert.d.ts +0 -14
  310. package/dist/apps/shared/components/mail/compose/SendFailureAlert.js +0 -11
@@ -2,68 +2,69 @@
2
2
  // Copyright (C) 2026 Jean-Philippe Steinmetz
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
- import React, { FormEvent, useEffect, useState } from "react";
5
+ import React, { useEffect, useState } from "react";
6
6
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
7
- import { AccessControlList, getMailboxAcl, grantMailboxAccess, revokeMailboxAccess } from "@rapidmx/react-shared/mail/mailApi.js";
7
+ import {
8
+ listMailboxAccess,
9
+ MailboxAccessMember,
10
+ MailboxAccessRole,
11
+ removeMailboxAccess,
12
+ setMailboxAccess,
13
+ } from "@rapidmx/react-shared/mail/mailboxAccessApi.js";
8
14
  import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
9
15
  import Button from "@rapidmx/react-shared/components/buttons/Button.js";
10
16
  import Modal from "@rapidmx/react-shared/components/overlays/Modal.js";
17
+ import PrincipalPicker from "../../sharing/PrincipalPicker.js";
11
18
 
12
- const DEFAULT_DELEGATE_ACTIONS = ["read", "list", "count", "exists"];
19
+ const ROLE_LABELS: Record<MailboxAccessRole, string> = { viewer: "Read only", manager: "Full access" };
13
20
 
14
21
  export interface ShareAccessCardProps {
15
22
  mailboxUid: string;
16
- /** The mailbox's owner - their own grant is shown but can't be revoked from here. */
23
+ /** The mailbox's owner: with one, only the owner can grant access to it. Without, the mailbox is shared and an
24
+ * administrator grants access here - to themselves included. */
17
25
  ownerUserUid?: string;
26
+ /** The signed-in administrator, for "Add me" on a shared mailbox. */
27
+ currentUserUid?: string;
28
+ }
29
+
30
+ function roleLabel(member: MailboxAccessMember): string {
31
+ if (member.role === "viewer") return ROLE_LABELS.viewer;
32
+ if (member.role === "manager") return ROLE_LABELS.manager;
33
+ return (member.actions ?? []).join(", ");
18
34
  }
19
35
 
20
36
  /**
21
- * Lets an admin (or, eventually, the mailbox owner) view and edit a mailbox's delegate access — the
22
- * mechanism behind Exchange-style shared mailboxes. `records` on a mailbox's own ACL doubles as both the
23
- * owner's grant (if any) and every delegate's — see `BaseMailboxRoute`'s doc comment in `@rapidmx/restapi`.
37
+ * A mailbox's members - the mechanism behind Exchange-style shared mailboxes - through the Sharing endpoints
38
+ * (`/mail/mailboxes/:id/access`), the audited way an administrator reaches a mailbox they hold no grant on. An
39
+ * administrator can review any mailbox's members and revoke any of them; they can grant access only on a shared
40
+ * (ownerless) mailbox - themselves included, which is how it appears in their own mail client. A personal mailbox is
41
+ * shared by its owner (or by an administrator impersonating them).
24
42
  */
25
- export default function ShareAccessCard({ mailboxUid, ownerUserUid }: ShareAccessCardProps) {
26
- const [acl, setAcl] = useState<AccessControlList | null>(null);
43
+ export default function ShareAccessCard({ mailboxUid, ownerUserUid, currentUserUid }: ShareAccessCardProps) {
44
+ const [members, setMembers] = useState<MailboxAccessMember[]>([]);
27
45
  const [loading, setLoading] = useState(true);
28
46
  const [error, setError] = useState<string | null>(null);
29
- const [notice, setNotice] = useState<string | null>(null);
30
- const [newUserUid, setNewUserUid] = useState("");
31
47
  const [saving, setSaving] = useState(false);
32
48
  const [revokeTarget, setRevokeTarget] = useState<string | null>(null);
49
+ // An entry that is not a user uid, being replaced with the user it was meant for.
50
+ const [replacing, setReplacing] = useState<MailboxAccessMember | null>(null);
33
51
 
34
52
  function reload() {
35
53
  setLoading(true);
36
54
  setError(null);
37
- getMailboxAcl(mailboxUid)
38
- .then(setAcl)
55
+ listMailboxAccess(mailboxUid)
56
+ .then(setMembers)
39
57
  .catch((err) => setError(err instanceof ApiRequestError ? err.message : "Could not load share settings."))
40
58
  .finally(() => setLoading(false));
41
59
  }
42
60
 
43
61
  useEffect(reload, [mailboxUid]);
44
62
 
45
- async function handleGrant(e: FormEvent) {
46
- e.preventDefault();
47
- const userUid = newUserUid.trim();
48
- if (!userUid) {
49
- return;
50
- }
63
+ async function addMe(userUid: string) {
51
64
  setSaving(true);
52
65
  setError(null);
53
- setNotice(null);
54
66
  try {
55
- // `grantMailboxAccess()` replaces any existing record for this uid, so granting read access to someone
56
- // who already has more (e.g. the owner) would silently downgrade them. Merge with their current actions.
57
- const current = await getMailboxAcl(mailboxUid);
58
- const existing = current.records.find((record) => record.userOrRoleId === userUid)?.actions ?? [];
59
- const missing = DEFAULT_DELEGATE_ACTIONS.filter((action) => !existing.includes(action));
60
- if (missing.length === 0) {
61
- setNotice(`${userUid} already has this access.`);
62
- setNewUserUid("");
63
- return;
64
- }
65
- await grantMailboxAccess(mailboxUid, userUid, [...existing, ...missing]);
66
- setNewUserUid("");
67
+ await setMailboxAccess(mailboxUid, userUid, "manager");
67
68
  reload();
68
69
  } catch (err) {
69
70
  setError(err instanceof ApiRequestError ? err.message : "Could not grant access.");
@@ -72,15 +73,33 @@ export default function ShareAccessCard({ mailboxUid, ownerUserUid }: ShareAcces
72
73
  }
73
74
  }
74
75
 
76
+ // Once the person is granted, the entry they replace (if any) is removed: the string it named never matched anyone.
77
+ async function handleGranted() {
78
+ const stale = replacing;
79
+ setReplacing(null);
80
+ let failure: string | null = null;
81
+ if (stale) {
82
+ try {
83
+ await removeMailboxAccess(mailboxUid, stale.userOrRoleId);
84
+ } catch (err) {
85
+ failure = err instanceof ApiRequestError ? err.message : "Could not remove the old entry.";
86
+ }
87
+ }
88
+ reload();
89
+ // After the reload, which clears the error it started with.
90
+ if (failure) {
91
+ setError(failure);
92
+ }
93
+ }
94
+
75
95
  // Only ever invoked from the revoke-confirmation modal below, which only renders once `revokeTarget` is set.
76
96
  async function handleRevoke() {
77
97
  const userOrRoleId = revokeTarget!;
78
98
  setRevokeTarget(null);
79
99
  setSaving(true);
80
100
  setError(null);
81
- setNotice(null);
82
101
  try {
83
- await revokeMailboxAccess(mailboxUid, userOrRoleId);
102
+ await removeMailboxAccess(mailboxUid, userOrRoleId);
84
103
  reload();
85
104
  } catch (err) {
86
105
  setError(err instanceof ApiRequestError ? err.message : "Could not revoke access.");
@@ -89,61 +108,89 @@ export default function ShareAccessCard({ mailboxUid, ownerUserUid }: ShareAcces
89
108
  }
90
109
  }
91
110
 
111
+ const shared = !ownerUserUid;
112
+ const isMember = members.some((member) => member.userOrRoleId === currentUserUid);
113
+
92
114
  return (
93
115
  <div className="bg-surface border border-border rounded-md p-6">
94
116
  <h2 className="text-base font-bold uppercase tracking-wide mb-1">Shared access</h2>
95
117
  <p className="text-sm text-text-muted mb-4">
96
- Grants read access to this mailbox for another user, independent of ownership.
118
+ {shared
119
+ ? "Who has access to this shared mailbox. Adding yourself is how it appears in your own mail client; every change is recorded in the audit log."
120
+ : "Who the owner has shared this mailbox with. You can review and revoke access; only the owner can grant it (impersonate them to do so)."}
97
121
  </p>
98
122
 
99
123
  {error && <Alert>{error}</Alert>}
100
- {notice && !error && <div className="mb-4 text-sm text-text-muted">{notice}</div>}
101
124
 
102
125
  {loading ? (
103
126
  <p className="text-sm text-text-muted">Loading&hellip;</p>
104
127
  ) : (
105
128
  <ul className="flex flex-col gap-2 mb-4">
106
- {(acl?.records ?? []).length === 0 && (
107
- <li className="text-sm text-text-muted">No grants on this mailbox yet.</li>
108
- )}
109
- {acl?.records.map((record) => (
129
+ {members.length === 0 && <li className="text-sm text-text-muted">No grants on this mailbox yet.</li>}
130
+ {members.map((member) => (
110
131
  <li
111
- key={record.userOrRoleId}
132
+ key={member.userOrRoleId}
112
133
  className="flex items-center justify-between gap-3 py-2 px-3 border border-border rounded-sm"
113
134
  >
114
135
  <div>
115
- <div className="text-sm font-medium">{record.userOrRoleId}</div>
116
- <div className="text-xs text-text-muted">{record.actions.join(", ")}</div>
136
+ <div className="text-sm font-medium">{member.userOrRoleId}</div>
137
+ <div className="text-xs text-text-muted">{roleLabel(member)}</div>
138
+ {member.noEffect && (
139
+ <div className="text-xs text-danger mt-0.5">
140
+ Not a user - this entry has no effect
141
+ {shared ? " - replace it with the user it was meant for or remove it." : " - remove it."}
142
+ </div>
143
+ )}
117
144
  </div>
118
- {record.userOrRoleId === ownerUserUid ? (
119
- <span className="text-xs font-bold uppercase tracking-wide text-text-muted">Owner</span>
120
- ) : (
145
+ <span className="flex items-center gap-3 shrink-0">
146
+ {member.noEffect && shared && (
147
+ <button
148
+ type="button"
149
+ onClick={() => setReplacing(member)}
150
+ disabled={saving}
151
+ className="text-sm text-primary-dark hover:underline disabled:opacity-55"
152
+ >
153
+ Replace with a user
154
+ </button>
155
+ )}
121
156
  <button
122
157
  type="button"
123
- onClick={() => setRevokeTarget(record.userOrRoleId)}
158
+ onClick={() => setRevokeTarget(member.userOrRoleId)}
124
159
  disabled={saving}
125
160
  className="text-sm text-danger hover:underline disabled:opacity-55"
126
161
  >
127
162
  Revoke
128
163
  </button>
129
- )}
164
+ </span>
130
165
  </li>
131
166
  ))}
132
167
  </ul>
133
168
  )}
134
169
 
135
- <form onSubmit={handleGrant} className="flex gap-2">
136
- <input
137
- type="text"
138
- value={newUserUid}
139
- onChange={(e) => setNewUserUid(e.target.value)}
140
- placeholder="User uid to grant access to"
141
- className="flex-1 text-sm py-2 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary"
142
- />
143
- <Button type="submit" loading={saving} disabled={saving} className="!w-auto">
144
- Grant
145
- </Button>
146
- </form>
170
+ {shared && (
171
+ <>
172
+ {currentUserUid && !isMember && !loading && (
173
+ <Button
174
+ type="button"
175
+ variant="secondary"
176
+ className="!w-auto mb-3"
177
+ disabled={saving}
178
+ onClick={() => void addMe(currentUserUid)}
179
+ >
180
+ Add me
181
+ </Button>
182
+ )}
183
+ <PrincipalPicker
184
+ key={replacing?.userOrRoleId ?? "new"}
185
+ mailboxUid={mailboxUid}
186
+ roleLabels={ROLE_LABELS}
187
+ initialPrincipal={replacing?.userOrRoleId}
188
+ defaultRole={replacing?.role === "manager" ? "manager" : "viewer"}
189
+ onGranted={handleGranted}
190
+ onCancel={replacing ? () => setReplacing(null) : undefined}
191
+ />
192
+ </>
193
+ )}
147
194
 
148
195
  <Modal open={revokeTarget !== null} onClose={() => setRevokeTarget(null)} title="Revoke access">
149
196
  <p className="text-sm mb-5">
@@ -16,12 +16,19 @@ import {
16
16
  } from "@rapidmx/react-shared/branding/brandingApi.js";
17
17
  import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
18
18
  import Button from "@rapidmx/react-shared/components/buttons/Button.js";
19
+ import CopyButton from "@rapidmx/react-shared/components/buttons/CopyButton.js";
19
20
 
20
21
  const INPUT_CLASS =
21
22
  "w-full text-sm py-2 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
22
23
 
23
24
  const MAX_UPLOAD_BYTES = 5 * 1024 * 1024;
24
25
 
26
+ /** A header that uses both variables - the snippet the Branding page offers to copy. */
27
+ export const HEADER_HTML_EXAMPLE = `<div style="display:flex; align-items:center; justify-content:space-between; padding:0.5rem 1rem">
28
+ <span>{APP_TITLE}</span>
29
+ <span>{USER_MENU}</span>
30
+ </div>`;
31
+
25
32
  /** SVG logo/icon uploads are refused (the server refuses them too): an SVG served from this origin can carry script. */
26
33
  export function isSvgFile(file: File): boolean {
27
34
  return file.type === "image/svg+xml" || file.name.toLowerCase().endsWith(".svg");
@@ -376,7 +383,21 @@ export default function BrandingForm({ branding, onChange, embedded = false }: B
376
383
  value={headerHtml}
377
384
  onChange={(e) => setHeaderHtml(e.target.value)}
378
385
  />
386
+ <span className="text-xs text-text-muted">
387
+ A header replaces the app's own title bar and the icon at the top of the icon rail, and stays at the top of the window. Write{" "}
388
+ <code>{"{USER_MENU}"}</code> where the account menu (avatar, Settings, Sign Out) should go, and <code>{"{APP_TITLE}"}</code>{" "}
389
+ where the name of the app on screen should show. Both work in the footer too. <code>{"{USER_MENU}"}</code> is replaced once
390
+ (the header's, else the footer's); without it the menu sits in a small cell at the right end of the header, so it is never lost.
391
+ Put it where your styles don't hide it on a phone.
392
+ </span>
379
393
  </label>
394
+ <div className="flex flex-col gap-1.5 text-sm" role="group" aria-label="Header example">
395
+ <div className="flex items-center justify-between gap-2">
396
+ <span className="font-semibold">Example header</span>
397
+ <CopyButton value={HEADER_HTML_EXAMPLE} label="Copy the example header HTML" />
398
+ </div>
399
+ <pre className="overflow-x-auto rounded-sm border border-border bg-surface-alt p-3 font-mono text-xs text-text">{HEADER_HTML_EXAMPLE}</pre>
400
+ </div>
380
401
  <label className="flex flex-col gap-1.5 text-sm">
381
402
  <span className="font-semibold">Footer HTML (optional)</span>
382
403
  <textarea
@@ -386,6 +407,9 @@ export default function BrandingForm({ branding, onChange, embedded = false }: B
386
407
  value={footerHtml}
387
408
  onChange={(e) => setFooterHtml(e.target.value)}
388
409
  />
410
+ <span className="text-xs text-text-muted">
411
+ <code>{"{APP_TITLE}"}</code> works here as well, and <code>{"{USER_MENU}"}</code> takes the account menu (opening upward) when the header has none.
412
+ </span>
389
413
  </label>
390
414
  <div>
391
415
  <Button type="submit" loading={saving} disabled={saving} className="!w-auto">