@rapidmx/web-client 0.14.1 → 0.16.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 (314) hide show
  1. package/README.md +373 -373
  2. package/apps/admin/branding/index.tsx +39 -39
  3. package/apps/admin/data-requests/index.tsx +482 -480
  4. package/apps/admin/domains/[uid].tsx +164 -163
  5. package/apps/admin/escrow-scopes/[uid].tsx +348 -348
  6. package/apps/admin/index.tsx +127 -124
  7. package/apps/admin/mailboxes/[uid].tsx +269 -224
  8. package/apps/admin/mailboxes/new/index.tsx +28 -28
  9. package/apps/admin/plugins/index.tsx +15 -15
  10. package/apps/admin/retention-policy/index.tsx +39 -39
  11. package/apps/admin/signing-certificates/index.tsx +343 -343
  12. package/apps/escrow/audit-log/index.tsx +196 -196
  13. package/apps/escrow/matters/[uid].tsx +621 -621
  14. package/apps/shared/appearance/AppearanceForm.tsx +9 -1
  15. package/apps/shared/auth/adminAccess.ts +99 -99
  16. package/apps/shared/calendar/bookingPlugin.ts +100 -0
  17. package/apps/shared/calendar/calendarLiveUpdates.ts +27 -0
  18. package/apps/shared/components/admin/layout/AdminShell.tsx +378 -346
  19. package/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.tsx +238 -0
  20. package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -152
  21. package/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.tsx +194 -0
  22. package/apps/shared/components/admin/settings/BrandingForm.tsx +423 -423
  23. package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +119 -119
  24. package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +53 -4
  25. package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +198 -198
  26. package/apps/shared/components/admin/settings/PluginsManager.tsx +64 -10
  27. package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +182 -182
  28. package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +288 -288
  29. package/apps/shared/components/admin/setup/SetupWizard.tsx +444 -444
  30. package/apps/shared/components/admin/usePagedList.tsx +129 -129
  31. package/apps/shared/components/calendar/AppointmentQuickForm.tsx +327 -0
  32. package/apps/shared/components/calendar/DescriptionEditor.tsx +274 -0
  33. package/apps/shared/components/calendar/EventDescriptionView.tsx +70 -0
  34. package/apps/shared/components/calendar/EventDetails.tsx +401 -0
  35. package/apps/shared/components/calendar/EventEditor.tsx +635 -0
  36. package/apps/shared/components/calendar/EventExpandedForm.tsx +210 -0
  37. package/apps/shared/components/calendar/EventFormParts.tsx +591 -0
  38. package/apps/shared/components/calendar/EventModal.tsx +206 -946
  39. package/apps/shared/components/calendar/EventQuickForm.tsx +116 -0
  40. package/apps/shared/components/calendar/EventShell.tsx +202 -0
  41. package/apps/shared/components/calendar/FindATime.tsx +379 -0
  42. package/apps/shared/components/calendar/GuestInput.tsx +100 -0
  43. package/apps/shared/components/calendar/LazyDescriptionEditor.tsx +70 -0
  44. package/apps/shared/components/calendar/MonthView.tsx +185 -173
  45. package/apps/shared/components/calendar/QuickCreateFaces.tsx +87 -0
  46. package/apps/shared/components/calendar/QuickCreateTabs.tsx +81 -0
  47. package/apps/shared/components/calendar/QuickFaceFrame.tsx +81 -0
  48. package/apps/shared/components/calendar/RecurrenceEditor.tsx +227 -222
  49. package/apps/shared/components/calendar/RequestChangeForm.tsx +240 -0
  50. package/apps/shared/components/calendar/SplitDayView.tsx +144 -143
  51. package/apps/shared/components/calendar/TaskQuickForm.tsx +289 -0
  52. package/apps/shared/components/calendar/TimeGridView.tsx +246 -244
  53. package/apps/shared/components/calendar/allDay.ts +124 -124
  54. package/apps/shared/components/calendar/eventDialogFields.ts +86 -0
  55. package/apps/shared/components/calendar/eventForm.ts +108 -0
  56. package/apps/shared/components/calendar/eventFormat.ts +210 -0
  57. package/apps/shared/components/calendar/findTimeGrid.ts +90 -0
  58. package/apps/shared/components/calendar/layout/CalendarShell.tsx +201 -200
  59. package/apps/shared/components/calendar/swipeNavigation.ts +14 -0
  60. package/apps/shared/components/contacts/ContactForm.tsx +383 -383
  61. package/apps/shared/components/contacts/ContactsSidebar.tsx +1 -1
  62. package/apps/shared/components/contacts/ContactsToolbar.tsx +103 -98
  63. package/apps/shared/components/contacts/layout/ContactsShell.tsx +217 -216
  64. package/apps/shared/components/escrow/layout/EscrowShell.tsx +155 -155
  65. package/apps/shared/components/layout/AppShell.tsx +480 -480
  66. package/apps/shared/components/layout/FloatingActionButton.tsx +31 -0
  67. package/apps/shared/components/layout/KeyEnrollmentGate.tsx +398 -398
  68. package/apps/shared/components/layout/MailboxProvisioning.tsx +168 -168
  69. package/apps/shared/components/layout/ResponsiveToolbar.tsx +315 -315
  70. package/apps/shared/components/layout/ThemeSwitch.tsx +84 -84
  71. package/apps/shared/components/layout/UserMenu.tsx +439 -372
  72. package/apps/shared/components/mail/ConversationList.tsx +323 -271
  73. package/apps/shared/components/mail/ConversationThreadPane.tsx +130 -5
  74. package/apps/shared/components/mail/InviteCard.tsx +387 -0
  75. package/apps/shared/components/mail/MailSelectionBar.tsx +236 -227
  76. package/apps/shared/components/mail/MessageDetailPane.tsx +1559 -1537
  77. package/apps/shared/components/mail/SwipeRow.tsx +120 -0
  78. package/apps/shared/components/mail/compose/ComposeContext.tsx +312 -312
  79. package/apps/shared/components/mail/compose/ComposeToolbar.tsx +422 -422
  80. package/apps/shared/components/mail/compose/ComposeWindow.tsx +1681 -1673
  81. package/apps/shared/components/mail/compose/RecipientInput.tsx +54 -11
  82. package/apps/shared/components/mail/compose/RichTextEditor.tsx +147 -147
  83. package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -60
  84. package/apps/shared/components/mail/compose/quotedBody.ts +161 -161
  85. package/apps/shared/components/mail/invite/InviteRowChip.tsx +104 -0
  86. package/apps/shared/components/mail/invite/InviteRsvpPopover.tsx +271 -0
  87. package/apps/shared/components/mail/invite/InviteTimeline.tsx +200 -0
  88. package/apps/shared/components/mail/invite/ProposeTimeForm.tsx +109 -0
  89. package/apps/shared/components/mail/invite/inviteFormat.ts +110 -0
  90. package/apps/shared/components/mail/invite/inviteStore.ts +114 -0
  91. package/apps/shared/components/mail/layout/FolderBadgeChip.tsx +21 -0
  92. package/apps/shared/components/mail/layout/MailShell.tsx +546 -490
  93. package/apps/shared/components/mail/layout/SidebarSection.tsx +66 -0
  94. package/apps/shared/components/mail/reading/PendingMessageCard.tsx +68 -0
  95. package/apps/shared/components/mail/verificationSeals.ts +125 -125
  96. package/apps/shared/components/rules/RuleBuilder.tsx +311 -311
  97. package/apps/shared/components/settings/SigningCertificateCard.tsx +344 -344
  98. package/apps/shared/components/settings/layout/SettingsShell.tsx +255 -253
  99. package/apps/shared/components/tasks/TasksSidebar.tsx +1 -1
  100. package/apps/shared/components/tasks/layout/TasksShell.tsx +218 -217
  101. package/apps/shared/gestures/useEnterSlide.ts +54 -0
  102. package/apps/shared/gestures/useSwipe.ts +114 -0
  103. package/apps/shared/gestures/useSwipeSlide.ts +113 -0
  104. package/apps/shared/gestures/useWheelPaging.ts +107 -0
  105. package/apps/shared/keyboard/GlobalShortcuts.tsx +51 -51
  106. package/apps/shared/keyboard/ShortcutProvider.tsx +62 -62
  107. package/apps/shared/keyboard/ShortcutsDialog.tsx +84 -84
  108. package/apps/shared/keyboard/dispatch.ts +124 -124
  109. package/apps/shared/keyboard/format.ts +89 -89
  110. package/apps/shared/keyboard/keymap.ts +114 -114
  111. package/apps/shared/keyboard/registry.ts +65 -65
  112. package/apps/shared/keyboard/targets.ts +79 -79
  113. package/apps/shared/mail/folderCounts.ts +17 -0
  114. package/apps/shared/mail/folderTree.ts +143 -143
  115. package/apps/shared/mail/listAllPages.ts +39 -39
  116. package/apps/shared/mail/newMailNotifications.ts +3 -15
  117. package/apps/shared/mail/outbox/outgoingReplies.ts +192 -0
  118. package/apps/shared/mail/outbox/sendJob.ts +19 -1
  119. package/apps/shared/mail/outbox/sendOutcomes.ts +13 -4
  120. package/apps/shared/mail/primaryMailbox.ts +71 -0
  121. package/apps/shared/mail/useCollapsedSections.ts +146 -0
  122. package/apps/shared/mail/useMailConnection.ts +205 -203
  123. package/apps/shared/mail/useMailLiveUpdates.ts +277 -277
  124. package/apps/shared/mail/useMarkMessageRead.ts +47 -47
  125. package/apps/shared/mail/useNewMailNotifications.ts +2 -2
  126. package/apps/shared/navigation/AppRouter.tsx +300 -300
  127. package/apps/shared/navigation/routerContext.tsx +83 -83
  128. package/apps/shared/notifications/preferences.ts +36 -0
  129. package/apps/shared/notifications/store.ts +9 -0
  130. package/apps/shared/search/LocalIndexLifecycle.tsx +114 -114
  131. package/apps/shared/search/crossMailboxSearch.ts +169 -0
  132. package/apps/shared/search/localIndexBuilder.ts +481 -481
  133. package/apps/shared/signing/enrollmentStorage.ts +33 -33
  134. package/apps/shared/signing/enrollmentTracker.ts +385 -385
  135. package/apps/shared/signing/enrollmentView.ts +251 -251
  136. package/apps/shared/signing/useNow.ts +19 -19
  137. package/apps/shared/signing/useSigningEnrollmentWatcher.ts +90 -90
  138. package/apps/shared/styles/app.css +396 -386
  139. package/apps/www/_routes.ts +1 -0
  140. package/apps/www/calendar/index.tsx +578 -469
  141. package/apps/www/contacts/[uid].tsx +109 -109
  142. package/apps/www/contacts/index.tsx +6 -0
  143. package/apps/www/index.tsx +2847 -2332
  144. package/apps/www/messages/[uid].tsx +135 -108
  145. package/apps/www/settings/auto-reply/index.tsx +133 -133
  146. package/apps/www/settings/encryption/index.tsx +1287 -1287
  147. package/apps/www/settings/filters/[uid].tsx +176 -176
  148. package/apps/www/settings/filters/index.tsx +102 -102
  149. package/apps/www/settings/filters/new/index.tsx +140 -140
  150. package/apps/www/settings/labels/index.tsx +204 -204
  151. package/apps/www/settings/privacy/index.tsx +492 -492
  152. package/apps/www/settings/profile/index.tsx +248 -0
  153. package/apps/www/settings/read-receipts/index.tsx +147 -147
  154. package/apps/www/settings/sharing/index.tsx +256 -256
  155. package/apps/www/settings/signatures/[uid].tsx +172 -172
  156. package/apps/www/settings/signatures/index.tsx +88 -88
  157. package/apps/www/settings/signatures/new/index.tsx +135 -135
  158. package/apps/www/tasks/index.tsx +649 -649
  159. package/dist/apps/admin/data-requests/index.js +1 -1
  160. package/dist/apps/admin/domains/[uid].js +4 -2
  161. package/dist/apps/admin/index.js +2 -1
  162. package/dist/apps/admin/mailboxes/[uid].js +12 -2
  163. package/dist/apps/shared/appearance/AppearanceForm.js +9 -1
  164. package/dist/apps/shared/calendar/bookingPlugin.d.ts +50 -0
  165. package/dist/apps/shared/calendar/bookingPlugin.js +57 -0
  166. package/dist/apps/shared/calendar/calendarLiveUpdates.d.ts +11 -0
  167. package/dist/apps/shared/calendar/calendarLiveUpdates.js +23 -0
  168. package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +1 -1
  169. package/dist/apps/shared/components/admin/layout/AdminShell.js +7 -3
  170. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.d.ts +35 -0
  171. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.js +115 -0
  172. package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.d.ts +16 -0
  173. package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.js +92 -0
  174. package/dist/apps/shared/components/admin/settings/BrandingForm.js +3 -3
  175. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +28 -4
  176. package/dist/apps/shared/components/admin/settings/PluginsManager.js +40 -6
  177. package/dist/apps/shared/components/calendar/AppointmentQuickForm.d.ts +47 -0
  178. package/dist/apps/shared/components/calendar/AppointmentQuickForm.js +135 -0
  179. package/dist/apps/shared/components/calendar/DescriptionEditor.d.ts +26 -0
  180. package/dist/apps/shared/components/calendar/DescriptionEditor.js +192 -0
  181. package/dist/apps/shared/components/calendar/EventDescriptionView.d.ts +14 -0
  182. package/dist/apps/shared/components/calendar/EventDescriptionView.js +39 -0
  183. package/dist/apps/shared/components/calendar/EventDetails.d.ts +33 -0
  184. package/dist/apps/shared/components/calendar/EventDetails.js +137 -0
  185. package/dist/apps/shared/components/calendar/EventEditor.d.ts +59 -0
  186. package/dist/apps/shared/components/calendar/EventEditor.js +544 -0
  187. package/dist/apps/shared/components/calendar/EventExpandedForm.d.ts +14 -0
  188. package/dist/apps/shared/components/calendar/EventExpandedForm.js +44 -0
  189. package/dist/apps/shared/components/calendar/EventFormParts.d.ts +70 -0
  190. package/dist/apps/shared/components/calendar/EventFormParts.js +191 -0
  191. package/dist/apps/shared/components/calendar/EventModal.d.ts +26 -13
  192. package/dist/apps/shared/components/calendar/EventModal.js +57 -459
  193. package/dist/apps/shared/components/calendar/EventQuickForm.d.ts +18 -0
  194. package/dist/apps/shared/components/calendar/EventQuickForm.js +25 -0
  195. package/dist/apps/shared/components/calendar/EventShell.d.ts +64 -0
  196. package/dist/apps/shared/components/calendar/EventShell.js +134 -0
  197. package/dist/apps/shared/components/calendar/FindATime.d.ts +18 -0
  198. package/dist/apps/shared/components/calendar/FindATime.js +190 -0
  199. package/dist/apps/shared/components/calendar/GuestInput.d.ts +45 -0
  200. package/dist/apps/shared/components/calendar/GuestInput.js +30 -0
  201. package/dist/apps/shared/components/calendar/LazyDescriptionEditor.d.ts +8 -0
  202. package/dist/apps/shared/components/calendar/LazyDescriptionEditor.js +44 -0
  203. package/dist/apps/shared/components/calendar/MonthView.d.ts +5 -1
  204. package/dist/apps/shared/components/calendar/MonthView.js +11 -5
  205. package/dist/apps/shared/components/calendar/QuickCreateFaces.d.ts +30 -0
  206. package/dist/apps/shared/components/calendar/QuickCreateFaces.js +44 -0
  207. package/dist/apps/shared/components/calendar/QuickCreateTabs.d.ts +24 -0
  208. package/dist/apps/shared/components/calendar/QuickCreateTabs.js +46 -0
  209. package/dist/apps/shared/components/calendar/QuickFaceFrame.d.ts +25 -0
  210. package/dist/apps/shared/components/calendar/QuickFaceFrame.js +19 -0
  211. package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +4 -1
  212. package/dist/apps/shared/components/calendar/RecurrenceEditor.js +2 -2
  213. package/dist/apps/shared/components/calendar/RequestChangeForm.d.ts +36 -0
  214. package/dist/apps/shared/components/calendar/RequestChangeForm.js +127 -0
  215. package/dist/apps/shared/components/calendar/SplitDayView.d.ts +3 -2
  216. package/dist/apps/shared/components/calendar/SplitDayView.js +3 -2
  217. package/dist/apps/shared/components/calendar/TaskQuickForm.d.ts +40 -0
  218. package/dist/apps/shared/components/calendar/TaskQuickForm.js +101 -0
  219. package/dist/apps/shared/components/calendar/TimeGridView.d.ts +4 -2
  220. package/dist/apps/shared/components/calendar/TimeGridView.js +3 -2
  221. package/dist/apps/shared/components/calendar/eventDialogFields.d.ts +28 -0
  222. package/dist/apps/shared/components/calendar/eventDialogFields.js +59 -0
  223. package/dist/apps/shared/components/calendar/eventForm.d.ts +98 -0
  224. package/dist/apps/shared/components/calendar/eventForm.js +1 -0
  225. package/dist/apps/shared/components/calendar/eventFormat.d.ts +80 -0
  226. package/dist/apps/shared/components/calendar/eventFormat.js +190 -0
  227. package/dist/apps/shared/components/calendar/findTimeGrid.d.ts +30 -0
  228. package/dist/apps/shared/components/calendar/findTimeGrid.js +83 -0
  229. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +3 -2
  230. package/dist/apps/shared/components/calendar/swipeNavigation.d.ts +9 -0
  231. package/dist/apps/shared/components/calendar/swipeNavigation.js +8 -0
  232. package/dist/apps/shared/components/contacts/ContactsSidebar.js +1 -1
  233. package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +3 -1
  234. package/dist/apps/shared/components/contacts/ContactsToolbar.js +4 -2
  235. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +4 -3
  236. package/dist/apps/shared/components/layout/FloatingActionButton.d.ts +13 -0
  237. package/dist/apps/shared/components/layout/FloatingActionButton.js +9 -0
  238. package/dist/apps/shared/components/layout/UserMenu.d.ts +14 -9
  239. package/dist/apps/shared/components/layout/UserMenu.js +74 -26
  240. package/dist/apps/shared/components/mail/ConversationList.d.ts +12 -1
  241. package/dist/apps/shared/components/mail/ConversationList.js +21 -4
  242. package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +4 -1
  243. package/dist/apps/shared/components/mail/ConversationThreadPane.js +127 -22
  244. package/dist/apps/shared/components/mail/InviteCard.d.ts +20 -0
  245. package/dist/apps/shared/components/mail/InviteCard.js +150 -0
  246. package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +6 -1
  247. package/dist/apps/shared/components/mail/MailSelectionBar.js +3 -3
  248. package/dist/apps/shared/components/mail/MessageDetailPane.js +13 -2
  249. package/dist/apps/shared/components/mail/SwipeRow.d.ts +22 -0
  250. package/dist/apps/shared/components/mail/SwipeRow.js +71 -0
  251. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +16 -7
  252. package/dist/apps/shared/components/mail/compose/RecipientInput.d.ts +21 -1
  253. package/dist/apps/shared/components/mail/compose/RecipientInput.js +18 -10
  254. package/dist/apps/shared/components/mail/invite/InviteRowChip.d.ts +23 -0
  255. package/dist/apps/shared/components/mail/invite/InviteRowChip.js +46 -0
  256. package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.d.ts +20 -0
  257. package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.js +141 -0
  258. package/dist/apps/shared/components/mail/invite/InviteTimeline.d.ts +27 -0
  259. package/dist/apps/shared/components/mail/invite/InviteTimeline.js +120 -0
  260. package/dist/apps/shared/components/mail/invite/ProposeTimeForm.d.ts +17 -0
  261. package/dist/apps/shared/components/mail/invite/ProposeTimeForm.js +45 -0
  262. package/dist/apps/shared/components/mail/invite/inviteFormat.d.ts +28 -0
  263. package/dist/apps/shared/components/mail/invite/inviteFormat.js +94 -0
  264. package/dist/apps/shared/components/mail/invite/inviteStore.d.ts +28 -0
  265. package/dist/apps/shared/components/mail/invite/inviteStore.js +95 -0
  266. package/dist/apps/shared/components/mail/layout/FolderBadgeChip.d.ts +6 -0
  267. package/dist/apps/shared/components/mail/layout/FolderBadgeChip.js +9 -0
  268. package/dist/apps/shared/components/mail/layout/MailShell.d.ts +10 -0
  269. package/dist/apps/shared/components/mail/layout/MailShell.js +76 -46
  270. package/dist/apps/shared/components/mail/layout/SidebarSection.d.ts +23 -0
  271. package/dist/apps/shared/components/mail/layout/SidebarSection.js +16 -0
  272. package/dist/apps/shared/components/mail/reading/PendingMessageCard.d.ts +14 -0
  273. package/dist/apps/shared/components/mail/reading/PendingMessageCard.js +16 -0
  274. package/dist/apps/shared/components/settings/layout/SettingsShell.js +7 -5
  275. package/dist/apps/shared/components/tasks/TasksSidebar.js +1 -1
  276. package/dist/apps/shared/components/tasks/layout/TasksShell.js +4 -3
  277. package/dist/apps/shared/gestures/useEnterSlide.d.ts +14 -0
  278. package/dist/apps/shared/gestures/useEnterSlide.js +47 -0
  279. package/dist/apps/shared/gestures/useSwipe.d.ts +45 -0
  280. package/dist/apps/shared/gestures/useSwipe.js +90 -0
  281. package/dist/apps/shared/gestures/useSwipeSlide.d.ts +40 -0
  282. package/dist/apps/shared/gestures/useSwipeSlide.js +95 -0
  283. package/dist/apps/shared/gestures/useWheelPaging.d.ts +32 -0
  284. package/dist/apps/shared/gestures/useWheelPaging.js +85 -0
  285. package/dist/apps/shared/mail/folderCounts.d.ts +10 -0
  286. package/dist/apps/shared/mail/folderCounts.js +12 -0
  287. package/dist/apps/shared/mail/newMailNotifications.d.ts +3 -8
  288. package/dist/apps/shared/mail/newMailNotifications.js +3 -12
  289. package/dist/apps/shared/mail/outbox/outgoingReplies.d.ts +80 -0
  290. package/dist/apps/shared/mail/outbox/outgoingReplies.js +131 -0
  291. package/dist/apps/shared/mail/outbox/sendJob.d.ts +5 -1
  292. package/dist/apps/shared/mail/outbox/sendJob.js +14 -1
  293. package/dist/apps/shared/mail/outbox/sendOutcomes.js +13 -4
  294. package/dist/apps/shared/mail/primaryMailbox.d.ts +29 -0
  295. package/dist/apps/shared/mail/primaryMailbox.js +61 -0
  296. package/dist/apps/shared/mail/useCollapsedSections.d.ts +32 -0
  297. package/dist/apps/shared/mail/useCollapsedSections.js +110 -0
  298. package/dist/apps/shared/mail/useMailConnection.js +3 -1
  299. package/dist/apps/shared/mail/useNewMailNotifications.js +3 -2
  300. package/dist/apps/shared/notifications/preferences.d.ts +13 -0
  301. package/dist/apps/shared/notifications/preferences.js +36 -0
  302. package/dist/apps/shared/notifications/store.d.ts +1 -0
  303. package/dist/apps/shared/notifications/store.js +7 -23
  304. package/dist/apps/shared/search/crossMailboxSearch.d.ts +72 -0
  305. package/dist/apps/shared/search/crossMailboxSearch.js +136 -0
  306. package/dist/apps/shared/styles/app.css +396 -386
  307. package/dist/apps/www/_routes.js +1 -0
  308. package/dist/apps/www/calendar/index.js +78 -7
  309. package/dist/apps/www/contacts/index.js +3 -1
  310. package/dist/apps/www/index.js +548 -210
  311. package/dist/apps/www/messages/[uid].js +13 -5
  312. package/dist/apps/www/settings/profile/index.d.ts +4 -0
  313. package/dist/apps/www/settings/profile/index.js +124 -0
  314. package/package.json +2 -2
@@ -2,29 +2,7 @@
2
2
  // Copyright (C) 2026 Jean-Philippe Steinmetz
3
3
  // SPDX-License-Identifier: MPL-2.0
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
- /**
6
- * The app's one notification store: every pop-up - new mail, a failed send, an API error, an expired session - goes through
7
- * `notify()`. It is deliberately framework-free (no React, no DOM beyond `sessionStorage`/timers), so it can be called from a hook,
8
- * a plain function or an `apiFetch` error path alike; `NotificationCenter` (the view, mounted once in the app frame) and
9
- * `useNotifications()` only *read* it.
10
- *
11
- * Rules, all enforced here rather than by the view so they hold whoever renders:
12
- *
13
- * - **At most `MAX_VISIBLE` (3) are visible**; the rest wait in a queue and appear as room is made. A sticky notification (an error, or
14
- * anything with actions) that finds the stack full pushes out the oldest one that would have gone by itself, rather than waiting behind
15
- * it. A queued notification that has waited `QUEUE_STALE_MS` is dropped (it would be news from the past) - it is still in the history.
16
- * - **Sticky until dismissed or resolved**: errors and notifications with actions never expire (`update()` or `dismiss()` resolve them).
17
- * Everything else goes by itself after its kind's default time, or `timeoutMs`. `sticky` overrides both ways.
18
- * - **A clock that stops**: a notification's remaining time stops while it is hovered or focused (`setPaused()`) and while the tab is
19
- * hidden (`setAllPaused()`), and continues from where it was.
20
- * - **Deduplicated by `dedupeKey`**: a second notification with a key that is still on screen (or waiting) does not stack - it replaces
21
- * the first one's content, restarts its clock and raises its `count`, so a flapping error is one pop-up saying "x3".
22
- * - **Nothing is lost when one goes**: the last `HISTORY_LIMIT` (30, except new-mail pop-ups, which the inbox already holds) are
23
- * kept, in memory and in `sessionStorage`, with which errors nobody has seen yet.
24
- *
25
- * Nothing is stored where there is no `window` (server-side rendering): the module state is shared between requests there, so
26
- * `notify()` only hands back an id.
27
- */
5
+ import { getNotificationsEnabled } from "./preferences.js";
28
6
  export const MAX_VISIBLE = 3;
29
7
  export const MAX_QUEUED = 20;
30
8
  export const QUEUE_STALE_MS = 30000;
@@ -254,6 +232,12 @@ export function notify(input) {
254
232
  paused: false,
255
233
  };
256
234
  applyInput(entry, input);
235
+ if (!getNotificationsEnabled()) {
236
+ // The user has pop-ups off: nothing is shown, but it is listed in the history like any other.
237
+ record(entry);
238
+ emit();
239
+ return id;
240
+ }
257
241
  const room = visibleCount() < MAX_VISIBLE;
258
242
  entries.push(entry);
259
243
  if (room) {
@@ -0,0 +1,72 @@
1
+ import type { SearchResult } from "@rapidmx/react-shared/search/searchApi.js";
2
+ /**
3
+ * How far a cross-mailbox search fans out. Exported (and mutable) so a test can shrink them instead of building 26 mailboxes or waiting a
4
+ * minute for a timeout; nothing else writes to it.
5
+ */
6
+ export declare const SEARCH_LIMITS: {
7
+ /** How many mailboxes are worked on at once. */
8
+ concurrency: number;
9
+ /** The most mailboxes one search covers - the caller's own first, then the shared ones (`orderMailboxes()`); a note says how many were left out. */
10
+ maxMailboxes: number;
11
+ /** How long one mailbox's Tier 1 (server) request may take before that mailbox is given up on, so one wedged mailbox cannot hold the search. */
12
+ tier1TimeoutMs: number;
13
+ /** The same for a mailbox's Tier 3 pass (fetching and decrypting up to a couple of hundred candidates, so much longer). */
14
+ tier3TimeoutMs: number;
15
+ /** The most result rows a search keeps on screen (the page's own cap for a list, `MAX_LOADED_ROWS`, applies to a search too). */
16
+ maxRows: number;
17
+ };
18
+ /**
19
+ * How many results each mailbox contributes to one page. One mailbox gives the whole page; with several the page is shared out between them
20
+ * (never below `MIN_MAILBOX_PAGE_SIZE`), so the merged first page stays about one page long instead of growing by the number of mailboxes.
21
+ */
22
+ export declare function searchPageSize(mailboxCount: number, pageSize: number): number;
23
+ /** A search hit that remembers which mailbox it was found in. */
24
+ export interface MailboxHit extends SearchResult {
25
+ mailboxUid: string;
26
+ }
27
+ export declare function tagHits(mailboxUid: string, hits: SearchResult[]): MailboxHit[];
28
+ /** One hit's identity across mailboxes: the same entity uid found in two mailboxes is two hits. */
29
+ export declare function hitKey(hit: {
30
+ mailboxUid: string;
31
+ entityUid: string;
32
+ }): string;
33
+ /**
34
+ * Merges Tier 1 (server, possibly `metadataOnly` for an encrypted message), Tier 2 (local index, fully decrypted and re-scored) and Tier 3
35
+ * (server-narrowed candidates, decrypted and re-scored) results into one ranked list, per `specs/search.md` §7's "client MUST re-score all
36
+ * results it can see... normalise into the same space rather than interleaving raw scores": each tier is normalized independently via
37
+ * `normalizeServerScores()` before merging, since a Postgres/OpenSearch score, a local `bm25()` score, and Tier 3's own term-count score all
38
+ * occupy unrelated ranges. A hit present in more than one list keeps only the last-inserted entry (Tier 2 wins over Tier 3 wins over Tier 1) -
39
+ * Tier 2 and Tier 3 both represent genuine, content-verified scores for the same message, so which one "wins" on overlap doesn't change
40
+ * correctness, only which of two equally-valid scores is shown; either supersedes Tier 1's metadata-only guess for the same message.
41
+ *
42
+ * Each tier's list is pooled across every mailbox searched before it is normalized, so one mailbox's best hit is not automatically "1.0"
43
+ * next to another's: the ranking is the same rule as for one mailbox, applied to the merged lists. A hit's identity is its mailbox and its
44
+ * entity uid (`hitKey()`), so the same uid can only collapse within a mailbox. Ties keep the order the lists were given in (a stable sort), which
45
+ * the caller makes the mailboxes' display order.
46
+ *
47
+ * Called progressively - each time with whatever tiers have reported so far (an empty array for the rest). Pure and stateless.
48
+ */
49
+ export declare function mergeSearchResults(tier1: MailboxHit[], tier2: MailboxHit[], tier3: MailboxHit[]): MailboxHit[];
50
+ /** Raised by `withTimeout()`. */
51
+ export declare class SearchTimeoutError extends Error {
52
+ constructor();
53
+ }
54
+ /** `promise`, or a rejection with `SearchTimeoutError` if it has not settled after `ms` (never, for a non-finite `ms`). The work is not aborted - a late answer is just dropped. */
55
+ export declare function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T>;
56
+ /**
57
+ * Runs `task` for every item, at most `concurrency` at a time, starting them in order. Stops starting new ones once `isCancelled()` (the search
58
+ * was superseded) or once one has rejected - which is then this function's own rejection, after the ones already running have settled.
59
+ */
60
+ export declare function runLimited<T>(items: readonly T[], concurrency: number, task: (item: T) => Promise<void>, isCancelled: () => boolean): Promise<void>;
61
+ /** Why one mailbox's search failed, as a short phrase for the notice: the class of failure, never the server's own text. */
62
+ export declare function classifyFailure(err: unknown): string;
63
+ /** A mailbox that could not be (fully) searched. `encrypted` is set when only its Tier 3 pass (the encrypted mail) failed - its other results are in. */
64
+ export interface MailboxFailure {
65
+ mailboxUid: string;
66
+ /** The mailbox's display name, as it was when the search ran. */
67
+ mailboxName: string;
68
+ encrypted: boolean;
69
+ reason: string;
70
+ }
71
+ /** The body of the "Some results may be missing" notice: which mailboxes, and why each. */
72
+ export declare function describeFailures(failures: readonly MailboxFailure[]): string;
@@ -0,0 +1,136 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * The pieces of searching several mailboxes at once (Mail's "All mailboxes" views, and a search widened from one mailbox's folder to every
7
+ * mailbox the reader can read). Nothing here talks to the server: `apps/www/index.tsx` fans its own per-mailbox pipeline (Tier 1 server search,
8
+ * Tier 2 local index, Tier 3 server-narrowed encrypted candidates) out across mailboxes and uses these to bound that fan-out, to merge what
9
+ * comes back into one ranked list and to say, in words, which mailbox could not be searched and why.
10
+ *
11
+ * A search of one mailbox is the same code with a list of one: nothing here changes what that returns.
12
+ */
13
+ import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
14
+ import { normalizeServerScores } from "@rapidmx/react-shared/search/searchScoring.js";
15
+ /**
16
+ * How far a cross-mailbox search fans out. Exported (and mutable) so a test can shrink them instead of building 26 mailboxes or waiting a
17
+ * minute for a timeout; nothing else writes to it.
18
+ */
19
+ export const SEARCH_LIMITS = {
20
+ /** How many mailboxes are worked on at once. */
21
+ concurrency: 4,
22
+ /** The most mailboxes one search covers - the caller's own first, then the shared ones (`orderMailboxes()`); a note says how many were left out. */
23
+ maxMailboxes: 25,
24
+ /** How long one mailbox's Tier 1 (server) request may take before that mailbox is given up on, so one wedged mailbox cannot hold the search. */
25
+ tier1TimeoutMs: 15000,
26
+ /** The same for a mailbox's Tier 3 pass (fetching and decrypting up to a couple of hundred candidates, so much longer). */
27
+ tier3TimeoutMs: 60000,
28
+ /** The most result rows a search keeps on screen (the page's own cap for a list, `MAX_LOADED_ROWS`, applies to a search too). */
29
+ maxRows: 500,
30
+ };
31
+ /** The least a mailbox is asked for on one page while several are searched, so a search over many mailboxes still moves at a sensible pace. */
32
+ const MIN_MAILBOX_PAGE_SIZE = 10;
33
+ /**
34
+ * How many results each mailbox contributes to one page. One mailbox gives the whole page; with several the page is shared out between them
35
+ * (never below `MIN_MAILBOX_PAGE_SIZE`), so the merged first page stays about one page long instead of growing by the number of mailboxes.
36
+ */
37
+ export function searchPageSize(mailboxCount, pageSize) {
38
+ return Math.max(MIN_MAILBOX_PAGE_SIZE, Math.ceil(pageSize / Math.max(1, mailboxCount)));
39
+ }
40
+ export function tagHits(mailboxUid, hits) {
41
+ return hits.map((hit) => ({ ...hit, mailboxUid }));
42
+ }
43
+ /** One hit's identity across mailboxes: the same entity uid found in two mailboxes is two hits. */
44
+ export function hitKey(hit) {
45
+ return `${hit.mailboxUid}\u0000${hit.entityUid}`;
46
+ }
47
+ /**
48
+ * Merges Tier 1 (server, possibly `metadataOnly` for an encrypted message), Tier 2 (local index, fully decrypted and re-scored) and Tier 3
49
+ * (server-narrowed candidates, decrypted and re-scored) results into one ranked list, per `specs/search.md` §7's "client MUST re-score all
50
+ * results it can see... normalise into the same space rather than interleaving raw scores": each tier is normalized independently via
51
+ * `normalizeServerScores()` before merging, since a Postgres/OpenSearch score, a local `bm25()` score, and Tier 3's own term-count score all
52
+ * occupy unrelated ranges. A hit present in more than one list keeps only the last-inserted entry (Tier 2 wins over Tier 3 wins over Tier 1) -
53
+ * Tier 2 and Tier 3 both represent genuine, content-verified scores for the same message, so which one "wins" on overlap doesn't change
54
+ * correctness, only which of two equally-valid scores is shown; either supersedes Tier 1's metadata-only guess for the same message.
55
+ *
56
+ * Each tier's list is pooled across every mailbox searched before it is normalized, so one mailbox's best hit is not automatically "1.0"
57
+ * next to another's: the ranking is the same rule as for one mailbox, applied to the merged lists. A hit's identity is its mailbox and its
58
+ * entity uid (`hitKey()`), so the same uid can only collapse within a mailbox. Ties keep the order the lists were given in (a stable sort), which
59
+ * the caller makes the mailboxes' display order.
60
+ *
61
+ * Called progressively - each time with whatever tiers have reported so far (an empty array for the rest). Pure and stateless.
62
+ */
63
+ export function mergeSearchResults(tier1, tier2, tier3) {
64
+ const merged = new Map();
65
+ for (const tier of [tier1, tier3, tier2]) {
66
+ for (const entry of normalizeServerScores(tier)) {
67
+ merged.set(hitKey(entry.result), entry);
68
+ }
69
+ }
70
+ return Array.from(merged.values())
71
+ .sort((a, b) => b.normalizedScore - a.normalizedScore)
72
+ .map((entry) => entry.result);
73
+ }
74
+ /** Raised by `withTimeout()`. */
75
+ export class SearchTimeoutError extends Error {
76
+ constructor() {
77
+ super("The search took too long.");
78
+ this.name = "SearchTimeoutError";
79
+ }
80
+ }
81
+ /** `promise`, or a rejection with `SearchTimeoutError` if it has not settled after `ms` (never, for a non-finite `ms`). The work is not aborted - a late answer is just dropped. */
82
+ export function withTimeout(promise, ms) {
83
+ if (!Number.isFinite(ms)) {
84
+ return promise;
85
+ }
86
+ return new Promise((resolve, reject) => {
87
+ const timer = setTimeout(() => reject(new SearchTimeoutError()), ms);
88
+ promise.then((value) => {
89
+ clearTimeout(timer);
90
+ resolve(value);
91
+ }, (reason) => {
92
+ clearTimeout(timer);
93
+ reject(reason);
94
+ });
95
+ });
96
+ }
97
+ /**
98
+ * Runs `task` for every item, at most `concurrency` at a time, starting them in order. Stops starting new ones once `isCancelled()` (the search
99
+ * was superseded) or once one has rejected - which is then this function's own rejection, after the ones already running have settled.
100
+ */
101
+ export async function runLimited(items, concurrency, task, isCancelled) {
102
+ let next = 0;
103
+ let failed = false;
104
+ const worker = async () => {
105
+ while (!failed && !isCancelled() && next < items.length) {
106
+ const item = items[next++];
107
+ try {
108
+ await task(item);
109
+ }
110
+ catch (err) {
111
+ failed = true;
112
+ throw err;
113
+ }
114
+ }
115
+ };
116
+ await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, worker));
117
+ }
118
+ /** Why one mailbox's search failed, as a short phrase for the notice: the class of failure, never the server's own text. */
119
+ export function classifyFailure(err) {
120
+ if (err instanceof SearchTimeoutError) {
121
+ return "timed out";
122
+ }
123
+ if (err instanceof ApiRequestError) {
124
+ if (err.status === 401 || err.status === 403) {
125
+ return "access denied";
126
+ }
127
+ return err.status >= 500 ? "server error" : "rejected by the server";
128
+ }
129
+ return "network error";
130
+ }
131
+ /** The body of the "Some results may be missing" notice: which mailboxes, and why each. */
132
+ export function describeFailures(failures) {
133
+ return `${failures
134
+ .map((failure) => `${failure.mailboxName} (${failure.encrypted ? "encrypted mail: " : ""}${failure.reason})`)
135
+ .join(", ")} could not be searched.`;
136
+ }