@rapidmx/web-client 0.4.0 → 0.6.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 (320) hide show
  1. package/README.md +88 -0
  2. package/apps/admin/audit-log/index.tsx +35 -8
  3. package/apps/admin/data-requests/index.tsx +480 -485
  4. package/apps/admin/distribution-lists/[uid].tsx +19 -1
  5. package/apps/admin/escrow-scopes/[uid].tsx +348 -237
  6. package/apps/admin/escrow-scopes/new/index.tsx +8 -2
  7. package/apps/admin/index.tsx +19 -1
  8. package/apps/admin/ingest-queue/index.tsx +44 -5
  9. package/apps/admin/mailboxes/[uid].tsx +211 -184
  10. package/apps/admin/quarantine/index.tsx +46 -14
  11. package/apps/admin/transport-rules/[uid].tsx +30 -1
  12. package/apps/admin/transport-rules/_transportRuleConfig.tsx +38 -2
  13. package/apps/admin/transport-rules/index.tsx +24 -6
  14. package/apps/admin/transport-rules/new/index.tsx +30 -1
  15. package/apps/escrow/_layout.tsx +2 -3
  16. package/apps/escrow/audit-log/index.tsx +196 -168
  17. package/apps/escrow/matters/[uid].tsx +621 -521
  18. package/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.tsx +22 -1
  19. package/apps/shared/components/admin/layout/AdminShell.tsx +28 -9
  20. package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -0
  21. package/apps/shared/components/admin/mailboxes/ResourceSettingsCard.tsx +3 -3
  22. package/apps/shared/components/admin/mailboxes/ShareAccessCard.tsx +55 -11
  23. package/apps/shared/components/admin/settings/BrandingForm.tsx +15 -4
  24. package/apps/shared/components/admin/settings/DomainDnsSetup.tsx +18 -7
  25. package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +10 -2
  26. package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +6 -0
  27. package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +45 -12
  28. package/apps/shared/components/admin/settings/PluginsManager.tsx +1235 -595
  29. package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +174 -98
  30. package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +49 -13
  31. package/apps/shared/components/admin/setup/SetupWizard.tsx +150 -34
  32. package/apps/shared/components/admin/signOut.ts +79 -0
  33. package/apps/shared/components/admin/usePagedList.tsx +129 -0
  34. package/apps/shared/components/calendar/EventModal.tsx +717 -549
  35. package/apps/shared/components/calendar/MonthView.tsx +173 -139
  36. package/apps/shared/components/calendar/RecurrenceEditor.tsx +222 -180
  37. package/apps/shared/components/calendar/SplitDayView.tsx +143 -137
  38. package/apps/shared/components/calendar/TimeGridView.tsx +244 -198
  39. package/apps/shared/components/calendar/allDay.ts +124 -0
  40. package/apps/shared/components/calendar/layout/CalendarShell.tsx +194 -192
  41. package/apps/shared/components/contacts/ContactDetailPane.tsx +100 -21
  42. package/apps/shared/components/contacts/ContactForm.tsx +377 -348
  43. package/apps/shared/components/contacts/ContactsSidebar.tsx +6 -2
  44. package/apps/shared/components/contacts/KeyChangeReview.tsx +192 -0
  45. package/apps/shared/components/contacts/contactKeys.ts +78 -0
  46. package/apps/shared/components/contacts/layout/ContactsShell.tsx +199 -197
  47. package/apps/shared/components/escrow/layout/EscrowShell.tsx +148 -134
  48. package/apps/shared/components/layout/AppShell.tsx +123 -33
  49. package/apps/shared/components/layout/BrandingChrome.tsx +48 -10
  50. package/apps/shared/components/layout/KeyEnrollmentGate.tsx +389 -298
  51. package/apps/shared/components/layout/MailboxProvisioning.tsx +19 -3
  52. package/apps/shared/components/layout/RecoveryCodeUnlock.tsx +350 -0
  53. package/apps/shared/components/layout/UnlockPromptProvider.tsx +257 -128
  54. package/apps/shared/components/mail/ConversationThreadPane.tsx +216 -181
  55. package/apps/shared/components/mail/MessageDetailPane.tsx +1318 -630
  56. package/apps/shared/components/mail/compose/ComposeContext.tsx +20 -15
  57. package/apps/shared/components/mail/compose/ComposeWindow.tsx +854 -132
  58. package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -0
  59. package/apps/shared/components/mail/layout/MailShell.tsx +420 -408
  60. package/apps/shared/components/mail/pinnedSigners.ts +124 -0
  61. package/apps/shared/components/mail/verificationSeals.ts +125 -0
  62. package/apps/shared/components/mail/writableMailboxes.ts +101 -0
  63. package/apps/shared/components/rules/RuleBuilder.tsx +311 -276
  64. package/apps/shared/components/settings/layout/SettingsShell.tsx +23 -9
  65. package/apps/shared/components/tasks/layout/TasksShell.tsx +201 -199
  66. package/apps/shared/mail/listAllPages.ts +39 -0
  67. package/apps/shared/plugins/pluginNav.ts +73 -0
  68. package/apps/shared/search/LocalIndexLifecycle.tsx +64 -55
  69. package/apps/shared/search/localIndexBuilder.ts +481 -179
  70. package/apps/shared/search/localIndexRpcClient.ts +231 -29
  71. package/apps/shared/search/localIndexSchema.ts +15 -6
  72. package/apps/shared/search/localIndexStorage.ts +98 -0
  73. package/apps/shared/search/localIndexVFS.ts +32 -1
  74. package/apps/shared/search/localIndexWorker.ts +648 -186
  75. package/apps/www/calendar/index.tsx +438 -417
  76. package/apps/www/contacts/[uid].tsx +21 -2
  77. package/apps/www/contacts/index.tsx +116 -12
  78. package/apps/www/index.tsx +1314 -1041
  79. package/apps/www/messages/[uid].tsx +18 -6
  80. package/apps/www/settings/auto-reply/index.tsx +134 -129
  81. package/apps/www/settings/encryption/index.tsx +739 -216
  82. package/apps/www/settings/filters/[uid].tsx +171 -155
  83. package/apps/www/settings/filters/new/index.tsx +8 -1
  84. package/apps/www/settings/focused-inbox/index.tsx +150 -148
  85. package/apps/www/settings/privacy/index.tsx +494 -436
  86. package/apps/www/settings/read-receipts/index.tsx +148 -125
  87. package/apps/www/settings/sharing/index.tsx +17 -14
  88. package/apps/www/tasks/index.tsx +638 -579
  89. package/dist/apps/admin/_404.d.ts +2 -0
  90. package/dist/apps/admin/_500.d.ts +2 -0
  91. package/dist/apps/admin/_layout.d.ts +8 -0
  92. package/dist/apps/admin/audit-log/index.d.ts +11 -0
  93. package/dist/apps/admin/audit-log/index.js +38 -8
  94. package/dist/apps/admin/branding/index.d.ts +3 -0
  95. package/dist/apps/admin/data-requests/index.d.ts +3 -0
  96. package/dist/apps/admin/data-requests/index.js +52 -72
  97. package/dist/apps/admin/distribution-lists/[uid].d.ts +7 -0
  98. package/dist/apps/admin/distribution-lists/[uid].js +1 -1
  99. package/dist/apps/admin/distribution-lists/index.d.ts +3 -0
  100. package/dist/apps/admin/distribution-lists/new/index.d.ts +3 -0
  101. package/dist/apps/admin/domains/[uid].d.ts +7 -0
  102. package/dist/apps/admin/domains/index.d.ts +3 -0
  103. package/dist/apps/admin/domains/new/index.d.ts +3 -0
  104. package/dist/apps/admin/encryption-policy/index.d.ts +3 -0
  105. package/dist/apps/admin/escrow-scopes/[uid].d.ts +21 -0
  106. package/dist/apps/admin/escrow-scopes/[uid].js +91 -12
  107. package/dist/apps/admin/escrow-scopes/index.d.ts +3 -0
  108. package/dist/apps/admin/escrow-scopes/new/index.d.ts +3 -0
  109. package/dist/apps/admin/escrow-scopes/new/index.js +8 -3
  110. package/dist/apps/admin/index.d.ts +3 -0
  111. package/dist/apps/admin/index.js +4 -1
  112. package/dist/apps/admin/ingest-queue/index.d.ts +4 -0
  113. package/dist/apps/admin/ingest-queue/index.js +24 -6
  114. package/dist/apps/admin/mailbox-policy/index.d.ts +3 -0
  115. package/dist/apps/admin/mailboxes/[uid].d.ts +7 -0
  116. package/dist/apps/admin/mailboxes/[uid].js +20 -4
  117. package/dist/apps/admin/mailboxes/new/index.d.ts +3 -0
  118. package/dist/apps/admin/plugins/index.d.ts +3 -0
  119. package/dist/apps/admin/quarantine/index.d.ts +6 -0
  120. package/dist/apps/admin/quarantine/index.js +20 -11
  121. package/dist/apps/admin/retention-policy/index.d.ts +3 -0
  122. package/dist/apps/admin/setup/index.d.ts +3 -0
  123. package/dist/apps/admin/transport-rules/[uid].d.ts +7 -0
  124. package/dist/apps/admin/transport-rules/[uid].js +18 -2
  125. package/dist/apps/admin/transport-rules/_transportRuleConfig.d.ts +21 -0
  126. package/dist/apps/admin/transport-rules/_transportRuleConfig.js +19 -0
  127. package/dist/apps/admin/transport-rules/index.d.ts +3 -0
  128. package/dist/apps/admin/transport-rules/index.js +22 -6
  129. package/dist/apps/admin/transport-rules/new/index.d.ts +3 -0
  130. package/dist/apps/admin/transport-rules/new/index.js +18 -2
  131. package/dist/apps/escrow/_layout.d.ts +10 -0
  132. package/dist/apps/escrow/_layout.js +3 -3
  133. package/dist/apps/escrow/audit-log/index.d.ts +9 -0
  134. package/dist/apps/escrow/audit-log/index.js +26 -1
  135. package/dist/apps/escrow/index.d.ts +3 -0
  136. package/dist/apps/escrow/matters/[uid].d.ts +7 -0
  137. package/dist/apps/escrow/matters/[uid].js +77 -42
  138. package/dist/apps/escrow/matters/new/index.d.ts +3 -0
  139. package/dist/apps/shared/components/admin/distributionLists/MemberListCard.d.ts +17 -0
  140. package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.d.ts +32 -0
  141. package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js +11 -2
  142. package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +32 -0
  143. package/dist/apps/shared/components/admin/layout/AdminShell.js +15 -6
  144. package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.d.ts +12 -0
  145. package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.js +72 -0
  146. package/dist/apps/shared/components/admin/mailboxes/MailboxTable.d.ts +6 -0
  147. package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.d.ts +19 -0
  148. package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.js +3 -3
  149. package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.d.ts +12 -0
  150. package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +22 -4
  151. package/dist/apps/shared/components/admin/settings/BrandingForm.d.ts +9 -0
  152. package/dist/apps/shared/components/admin/settings/BrandingForm.js +15 -4
  153. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.d.ts +12 -0
  154. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +13 -7
  155. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.d.ts +12 -0
  156. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +7 -2
  157. package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.d.ts +9 -0
  158. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.d.ts +19 -0
  159. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +6 -0
  160. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.d.ts +10 -0
  161. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +34 -12
  162. package/dist/apps/shared/components/admin/settings/PluginsManager.d.ts +4 -0
  163. package/dist/apps/shared/components/admin/settings/PluginsManager.js +390 -78
  164. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.d.ts +9 -0
  165. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +40 -11
  166. package/dist/apps/shared/components/admin/setup/EscrowSetupStep.d.ts +14 -0
  167. package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +29 -13
  168. package/dist/apps/shared/components/admin/setup/SetupWizard.d.ts +36 -0
  169. package/dist/apps/shared/components/admin/setup/SetupWizard.js +87 -21
  170. package/dist/apps/shared/components/admin/signOut.d.ts +23 -0
  171. package/dist/apps/shared/components/admin/signOut.js +75 -0
  172. package/dist/apps/shared/components/admin/usePagedList.d.ts +39 -0
  173. package/dist/apps/shared/components/admin/usePagedList.js +99 -0
  174. package/dist/apps/shared/components/calendar/CalendarListSidebar.d.ts +26 -0
  175. package/dist/apps/shared/components/calendar/EventModal.d.ts +46 -0
  176. package/dist/apps/shared/components/calendar/EventModal.js +142 -21
  177. package/dist/apps/shared/components/calendar/MonthView.d.ts +15 -0
  178. package/dist/apps/shared/components/calendar/MonthView.js +12 -5
  179. package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +20 -0
  180. package/dist/apps/shared/components/calendar/RecurrenceEditor.js +40 -5
  181. package/dist/apps/shared/components/calendar/ResourcePicker.d.ts +19 -0
  182. package/dist/apps/shared/components/calendar/SplitDayView.d.ts +28 -0
  183. package/dist/apps/shared/components/calendar/SplitDayView.js +10 -4
  184. package/dist/apps/shared/components/calendar/TimeGridView.d.ts +17 -0
  185. package/dist/apps/shared/components/calendar/TimeGridView.js +23 -7
  186. package/dist/apps/shared/components/calendar/allDay.d.ts +51 -0
  187. package/dist/apps/shared/components/calendar/allDay.js +111 -0
  188. package/dist/apps/shared/components/calendar/layout/CalendarShell.d.ts +40 -0
  189. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +3 -3
  190. package/dist/apps/shared/components/contacts/ContactDetailPane.d.ts +23 -0
  191. package/dist/apps/shared/components/contacts/ContactDetailPane.js +43 -5
  192. package/dist/apps/shared/components/contacts/ContactForm.d.ts +20 -0
  193. package/dist/apps/shared/components/contacts/ContactForm.js +32 -10
  194. package/dist/apps/shared/components/contacts/ContactsSidebar.d.ts +40 -0
  195. package/dist/apps/shared/components/contacts/ContactsSidebar.js +2 -2
  196. package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +25 -0
  197. package/dist/apps/shared/components/contacts/KeyChangeReview.d.ts +40 -0
  198. package/dist/apps/shared/components/contacts/KeyChangeReview.js +63 -0
  199. package/dist/apps/shared/components/contacts/contactKeys.d.ts +29 -0
  200. package/dist/apps/shared/components/contacts/contactKeys.js +64 -0
  201. package/dist/apps/shared/components/contacts/layout/ContactsShell.d.ts +21 -0
  202. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +2 -2
  203. package/dist/apps/shared/components/escrow/layout/EscrowShell.d.ts +25 -0
  204. package/dist/apps/shared/components/escrow/layout/EscrowShell.js +24 -5
  205. package/dist/apps/shared/components/forms/StringListField.d.ts +22 -0
  206. package/dist/apps/shared/components/layout/AppShell.d.ts +49 -0
  207. package/dist/apps/shared/components/layout/AppShell.js +97 -26
  208. package/dist/apps/shared/components/layout/BrandingChrome.d.ts +18 -0
  209. package/dist/apps/shared/components/layout/BrandingChrome.js +45 -10
  210. package/dist/apps/shared/components/layout/KeyEnrollmentGate.d.ts +51 -0
  211. package/dist/apps/shared/components/layout/KeyEnrollmentGate.js +49 -12
  212. package/dist/apps/shared/components/layout/MailboxProvisioning.d.ts +13 -0
  213. package/dist/apps/shared/components/layout/MailboxProvisioning.js +10 -2
  214. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.d.ts +66 -0
  215. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.js +174 -0
  216. package/dist/apps/shared/components/layout/UnlockPromptProvider.d.ts +45 -0
  217. package/dist/apps/shared/components/layout/UnlockPromptProvider.js +73 -14
  218. package/dist/apps/shared/components/layout/UserMenu.d.ts +23 -0
  219. package/dist/apps/shared/components/mail/ConversationList.d.ts +11 -0
  220. package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +23 -0
  221. package/dist/apps/shared/components/mail/ConversationThreadPane.js +50 -12
  222. package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +93 -0
  223. package/dist/apps/shared/components/mail/MessageDetailPane.js +441 -36
  224. package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +58 -0
  225. package/dist/apps/shared/components/mail/compose/ComposeContext.js +9 -6
  226. package/dist/apps/shared/components/mail/compose/ComposeToolbar.d.ts +15 -0
  227. package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +37 -0
  228. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +699 -128
  229. package/dist/apps/shared/components/mail/compose/EmojiPicker.d.ts +14 -0
  230. package/dist/apps/shared/components/mail/compose/GifPicker.d.ts +13 -0
  231. package/dist/apps/shared/components/mail/compose/RichTextEditor.d.ts +34 -0
  232. package/dist/apps/shared/components/mail/compose/ScheduleSendPicker.d.ts +16 -0
  233. package/dist/apps/shared/components/mail/compose/composeFlushRegistry.d.ts +27 -0
  234. package/dist/apps/shared/components/mail/compose/composeFlushRegistry.js +50 -0
  235. package/dist/apps/shared/components/mail/layout/MailShell.d.ts +57 -0
  236. package/dist/apps/shared/components/mail/layout/MailShell.js +13 -4
  237. package/dist/apps/shared/components/mail/pinnedSigners.d.ts +33 -0
  238. package/dist/apps/shared/components/mail/pinnedSigners.js +98 -0
  239. package/dist/apps/shared/components/mail/verificationSeals.d.ts +22 -0
  240. package/dist/apps/shared/components/mail/verificationSeals.js +112 -0
  241. package/dist/apps/shared/components/mail/writableMailboxes.d.ts +15 -0
  242. package/dist/apps/shared/components/mail/writableMailboxes.js +87 -0
  243. package/dist/apps/shared/components/rules/RuleBuilder.d.ts +70 -0
  244. package/dist/apps/shared/components/rules/RuleBuilder.js +34 -6
  245. package/dist/apps/shared/components/settings/layout/SettingsShell.d.ts +41 -0
  246. package/dist/apps/shared/components/settings/layout/SettingsShell.js +19 -9
  247. package/dist/apps/shared/components/tasks/TasksSidebar.d.ts +41 -0
  248. package/dist/apps/shared/components/tasks/TasksToolbar.d.ts +14 -0
  249. package/dist/apps/shared/components/tasks/layout/TasksShell.d.ts +24 -0
  250. package/dist/apps/shared/components/tasks/layout/TasksShell.js +2 -2
  251. package/dist/apps/shared/mail/findWellKnownFolderUid.d.ts +5 -0
  252. package/dist/apps/shared/mail/listAllPages.d.ts +17 -0
  253. package/dist/apps/shared/mail/listAllPages.js +25 -0
  254. package/dist/apps/shared/plugins/pluginNav.d.ts +39 -0
  255. package/dist/apps/shared/plugins/pluginNav.js +33 -0
  256. package/dist/apps/shared/search/LocalIndexLifecycle.d.ts +13 -0
  257. package/dist/apps/shared/search/LocalIndexLifecycle.js +58 -54
  258. package/dist/apps/shared/search/localIndexBlockCipher.d.ts +36 -0
  259. package/dist/apps/shared/search/localIndexBuilder.d.ts +85 -0
  260. package/dist/apps/shared/search/localIndexBuilder.js +292 -37
  261. package/dist/apps/shared/search/localIndexKey.d.ts +4 -0
  262. package/dist/apps/shared/search/localIndexRpcClient.d.ts +71 -0
  263. package/dist/apps/shared/search/localIndexRpcClient.js +191 -26
  264. package/dist/apps/shared/search/localIndexSchema.d.ts +111 -0
  265. package/dist/apps/shared/search/localIndexSchema.js +12 -6
  266. package/dist/apps/shared/search/localIndexSizePreference.d.ts +27 -0
  267. package/dist/apps/shared/search/localIndexStorage.d.ts +28 -0
  268. package/dist/apps/shared/search/localIndexStorage.js +86 -0
  269. package/dist/apps/shared/search/localIndexVFS.d.ts +101 -0
  270. package/dist/apps/shared/search/localIndexVFS.js +68 -40
  271. package/dist/apps/shared/search/localIndexWorker.d.ts +145 -0
  272. package/dist/apps/shared/search/localIndexWorker.js +519 -173
  273. package/dist/apps/shared/search/searchTier2.d.ts +30 -0
  274. package/dist/apps/www/_404.d.ts +2 -0
  275. package/dist/apps/www/_500.d.ts +2 -0
  276. package/dist/apps/www/_layout.d.ts +14 -0
  277. package/dist/apps/www/calendar/index.d.ts +3 -0
  278. package/dist/apps/www/calendar/index.js +28 -10
  279. package/dist/apps/www/contacts/[uid].d.ts +13 -0
  280. package/dist/apps/www/contacts/[uid].js +13 -2
  281. package/dist/apps/www/contacts/index.d.ts +3 -0
  282. package/dist/apps/www/contacts/index.js +80 -10
  283. package/dist/apps/www/index.d.ts +3 -0
  284. package/dist/apps/www/index.js +339 -108
  285. package/dist/apps/www/messages/[uid].d.ts +11 -0
  286. package/dist/apps/www/messages/[uid].js +18 -6
  287. package/dist/apps/www/settings/auto-reply/index.d.ts +4 -0
  288. package/dist/apps/www/settings/auto-reply/index.js +9 -4
  289. package/dist/apps/www/settings/encryption/index.d.ts +7 -0
  290. package/dist/apps/www/settings/encryption/index.js +514 -97
  291. package/dist/apps/www/settings/filters/[uid].d.ts +8 -0
  292. package/dist/apps/www/settings/filters/[uid].js +22 -7
  293. package/dist/apps/www/settings/filters/_mailFilterRuleConfig.d.ts +11 -0
  294. package/dist/apps/www/settings/filters/index.d.ts +4 -0
  295. package/dist/apps/www/settings/filters/new/index.d.ts +4 -0
  296. package/dist/apps/www/settings/filters/new/index.js +8 -2
  297. package/dist/apps/www/settings/focused-inbox/index.d.ts +4 -0
  298. package/dist/apps/www/settings/focused-inbox/index.js +3 -1
  299. package/dist/apps/www/settings/labels/index.d.ts +4 -0
  300. package/dist/apps/www/settings/privacy/index.d.ts +4 -0
  301. package/dist/apps/www/settings/privacy/index.js +57 -22
  302. package/dist/apps/www/settings/read-receipts/index.d.ts +4 -0
  303. package/dist/apps/www/settings/read-receipts/index.js +10 -3
  304. package/dist/apps/www/settings/sharing/index.d.ts +4 -0
  305. package/dist/apps/www/settings/sharing/index.js +7 -11
  306. package/dist/apps/www/settings/signatures/[uid].d.ts +8 -0
  307. package/dist/apps/www/settings/signatures/index.d.ts +4 -0
  308. package/dist/apps/www/settings/signatures/new/index.d.ts +4 -0
  309. package/dist/apps/www/settings/signatures/signatureDefaults.d.ts +10 -0
  310. package/dist/apps/www/tasks/index.d.ts +3 -0
  311. package/dist/apps/www/tasks/index.js +50 -10
  312. package/package.json +3 -3
  313. package/apps/shared/components/booking/AvailabilityEditor.tsx +0 -118
  314. package/apps/www/settings/booking-types/[uid].tsx +0 -300
  315. package/apps/www/settings/booking-types/index.tsx +0 -98
  316. package/apps/www/settings/booking-types/new/index.tsx +0 -212
  317. package/dist/apps/shared/components/booking/AvailabilityEditor.js +0 -45
  318. package/dist/apps/www/settings/booking-types/[uid].js +0 -129
  319. package/dist/apps/www/settings/booking-types/index.js +0 -29
  320. package/dist/apps/www/settings/booking-types/new/index.js +0 -86
@@ -8,7 +8,7 @@ import { MailboxAutoProvisionAliasOption, autoProvisionMailbox } from "@rapidmx/
8
8
  import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
9
9
  import Button from "@rapidmx/react-shared/components/buttons/Button.js";
10
10
 
11
- type Status = "checking" | "needs_selection" | "creating" | "unavailable";
11
+ type Status = "checking" | "needs_selection" | "creating" | "unavailable" | "retryable";
12
12
 
13
13
  /**
14
14
  * Rendered by each app's shell (Mail/Calendar/Contacts/Tasks) *instead of* the normal `AppShell`
@@ -27,7 +27,11 @@ export default function MailboxProvisioning() {
27
27
  const [selected, setSelected] = useState("");
28
28
  const [error, setError] = useState<string | null>(null);
29
29
 
30
+ // Bumped by "Retry" to re-run the check below.
31
+ const [attempt, setAttempt] = useState(0);
32
+
30
33
  useEffect(() => {
34
+ setStatus("checking");
31
35
  autoProvisionMailbox()
32
36
  .then((result) => {
33
37
  if (result.status === "needs_selection") {
@@ -44,8 +48,10 @@ export default function MailboxProvisioning() {
44
48
  window.location.reload();
45
49
  }
46
50
  })
47
- .catch(() => setStatus("unavailable"));
48
- }, []);
51
+ // A 503 means the server couldn't read its own provisioning policy right now - not that there's no
52
+ // mailbox to be had - so it gets a retry instead of the permanent "ask an administrator" message.
53
+ .catch((err) => setStatus(err instanceof ApiRequestError && err.status === 503 ? "retryable" : "unavailable"));
54
+ }, [attempt]);
49
55
 
50
56
  async function handleConfirm() {
51
57
  // `selected` only ever takes a value from `options` itself (the initial default, or the
@@ -90,6 +96,16 @@ export default function MailboxProvisioning() {
90
96
  </Button>
91
97
  </div>
92
98
  );
99
+ } else if (status === "retryable") {
100
+ content = (
101
+ <>
102
+ <h1 className="text-lg font-bold uppercase tracking-wide">Couldn&rsquo;t check right now</h1>
103
+ <p className="text-sm text-text-muted">We couldn&rsquo;t check whether a mailbox can be set up for you. Please try again.</p>
104
+ <Button type="button" onClick={() => setAttempt((n) => n + 1)} className="!w-auto self-center">
105
+ Retry
106
+ </Button>
107
+ </>
108
+ );
93
109
  } else {
94
110
  content = (
95
111
  <>
@@ -0,0 +1,350 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * Unlocking with a recovery code, and what has to happen after it. A recovery code is single-use: once it has opened
7
+ * the keys, the user may set a new encryption password (`replacePasswordWrap()`), and then the used code is removed
8
+ * (`consumeRecoveryCode()`). The order matters - react-shared's `replacePasswordWrap()` refuses unless another own
9
+ * unlock method remains, and the not-yet-consumed code is that method.
10
+ *
11
+ * `UnlockPromptProvider` and `KeyEnrollmentGate` both unlock with `startRecoveryUnlock()`, settle whatever was waiting
12
+ * on the unlock straight away, and then show `RecoveryFollowUpModal` for the follow-up steps.
13
+ */
14
+ import React, { FormEvent, useState } from "react";
15
+ import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
16
+ import { getUnlockedKeys, unlockWithRecoveryCode } from "@rapidmx/react-shared/crypto/keySession.js";
17
+ import { getKeyVault, type PublicKey } from "@rapidmx/react-shared/crypto/keyvaultApi.js";
18
+ import { KeysLockedError } from "@rapidmx/react-shared/crypto/masterKey.js";
19
+ import {
20
+ PasswordWrapReplaceError,
21
+ consumeRecoveryCode,
22
+ replacePasswordWrap,
23
+ } from "@rapidmx/react-shared/crypto/masterKeyWraps.js";
24
+ import Modal from "@rapidmx/react-shared/components/overlays/Modal.js";
25
+ import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
26
+ import Button from "@rapidmx/react-shared/components/buttons/Button.js";
27
+ import FormField from "@rapidmx/react-shared/components/forms/FormField.js";
28
+
29
+ /** The same minimum every other "set an encryption password" form in this app uses. */
30
+ export const MIN_PASSWORD_LENGTH = 8;
31
+
32
+ /** Where recovery codes are regenerated. */
33
+ export const ENCRYPTION_SETTINGS_HREF = "/settings/encryption";
34
+
35
+ /** Deliberately generic: a wrong code and a vault with no recovery codes fail the same way. */
36
+ export const RECOVERY_CODE_ERROR = "That recovery code didn't work.";
37
+
38
+ export const REPLACE_ROTATED_MESSAGE =
39
+ "Your encryption keys were changed on another device after you unlocked, so your password wasn't changed and your recovery code wasn't used. Reload the page and unlock again.";
40
+ export const REPLACE_MULTIPLE_PASSWORDS_MESSAGE =
41
+ "This mailbox has more than one encryption password, so it can't be replaced here. Nothing was changed. Remove the extra password in Settings > Encryption first.";
42
+ export const REPLACE_NO_OTHER_METHOD_MESSAGE =
43
+ "Your password wasn't changed, because this mailbox would be left with no other way to unlock. Your recovery code may already have been used in another window. Nothing was changed.";
44
+ export const REPLACE_ADD_FAILED_RESTORED_MESSAGE =
45
+ "Your new password couldn't be saved, so your old password still works. Nothing was changed. Try again.";
46
+ export const REPLACE_ADD_FAILED_NOT_RESTORED_MESSAGE =
47
+ "Your new password couldn't be saved, and your old password couldn't be put back, so this mailbox has no password right now. Your recovery code still works. Try again, or keep the code for now.";
48
+ export const REPLACE_LOCKED_MESSAGE =
49
+ "Your encryption keys were locked before your new password could be set, so nothing was changed and your recovery code still works. Unlock with it again to set a new password.";
50
+ export const REPLACE_GENERIC_MESSAGE = "Your new password couldn't be saved. Nothing was changed. Try again.";
51
+ export const CONSUME_FAILED_MESSAGE =
52
+ "The recovery code you used couldn't be removed, so it may still work. Regenerate your recovery codes in Settings > Encryption to make sure it can't be used again.";
53
+
54
+ /** What a successful recovery-code unlock hands to `RecoveryFollowUpModal`. */
55
+ export interface RecoveryFollowUp {
56
+ mailboxUid: string;
57
+ recoveryMethodId?: string;
58
+ /** The codes left once the used one is consumed. */
59
+ remainingRecoveryCodes: number;
60
+ /** The vault's generation read *before* the unlock - see `startRecoveryUnlock()`. */
61
+ expectedMasterKeyGeneration?: number;
62
+ unopenableKeys: string[];
63
+ }
64
+
65
+ /**
66
+ * Unlocks `mailboxUid` with a recovery code (normalized by react-shared, so spacing and case don't matter). The
67
+ * vault's `masterKeyGeneration` is read first: if another device rotates the master key at any point after that read,
68
+ * the generation passed to `replacePasswordWrap()` later is stale and the replacement is refused, never written with
69
+ * a dead master key. A failed read just means no generation check. Rejects exactly as `unlockWithRecoveryCode()` does.
70
+ */
71
+ export async function startRecoveryUnlock(mailboxUid: string, mailboxKeys: PublicKey[], code: string): Promise<RecoveryFollowUp> {
72
+ const expectedMasterKeyGeneration = await getKeyVault(mailboxUid).then(
73
+ (vault) => vault.masterKeyGeneration,
74
+ () => undefined,
75
+ );
76
+ const result = await unlockWithRecoveryCode(mailboxUid, mailboxKeys, code);
77
+ return {
78
+ mailboxUid,
79
+ recoveryMethodId: result.recoveryMethodId,
80
+ remainingRecoveryCodes: result.remainingRecoveryCodes,
81
+ expectedMasterKeyGeneration,
82
+ unopenableKeys: result.unopenableKeys,
83
+ };
84
+ }
85
+
86
+ /** A "use a recovery code instead" / "use your password instead" switch for an unlock form. */
87
+ export function UnlockModeToggle({
88
+ mode,
89
+ disabled,
90
+ onChange,
91
+ }: {
92
+ mode: "password" | "recovery";
93
+ disabled: boolean;
94
+ onChange: (mode: "password" | "recovery") => void;
95
+ }) {
96
+ return (
97
+ <Button
98
+ type="button"
99
+ variant="text"
100
+ className="!w-auto"
101
+ disabled={disabled}
102
+ onClick={() => onChange(mode === "password" ? "recovery" : "password")}
103
+ >
104
+ {mode === "password" ? "Use a recovery code instead" : "Use your password instead"}
105
+ </Button>
106
+ );
107
+ }
108
+
109
+ type Step = "password" | "done";
110
+
111
+ /** Why the new-password form is no longer offered, with the message to show. `reload` adds a Reload button. */
112
+ interface Blocked {
113
+ message: string;
114
+ reload?: boolean;
115
+ /** The secondary Skip / Keep action is still offered (e.g. two password wraps - nothing else is wrong). */
116
+ allowSecondary?: boolean;
117
+ }
118
+
119
+ function replaceFailure(err: unknown): { message: string; blocked?: Blocked } {
120
+ if (err instanceof PasswordWrapReplaceError) {
121
+ switch (err.reason) {
122
+ case "master_key_rotated":
123
+ return { message: REPLACE_ROTATED_MESSAGE, blocked: { message: REPLACE_ROTATED_MESSAGE, reload: true } };
124
+ case "multiple_password_wraps":
125
+ return {
126
+ message: REPLACE_MULTIPLE_PASSWORDS_MESSAGE,
127
+ blocked: { message: REPLACE_MULTIPLE_PASSWORDS_MESSAGE, allowSecondary: true },
128
+ };
129
+ case "no_other_unlock_method":
130
+ return { message: REPLACE_NO_OTHER_METHOD_MESSAGE, blocked: { message: REPLACE_NO_OTHER_METHOD_MESSAGE } };
131
+ default:
132
+ return { message: err.restored ? REPLACE_ADD_FAILED_RESTORED_MESSAGE : REPLACE_ADD_FAILED_NOT_RESTORED_MESSAGE };
133
+ }
134
+ }
135
+ if (err instanceof KeysLockedError) {
136
+ return { message: REPLACE_LOCKED_MESSAGE, blocked: { message: REPLACE_LOCKED_MESSAGE } };
137
+ }
138
+ return { message: err instanceof ApiRequestError ? `${REPLACE_GENERIC_MESSAGE} (${err.message})` : REPLACE_GENERIC_MESSAGE };
139
+ }
140
+
141
+ export interface RecoveryFollowUpModalProps {
142
+ followUp: RecoveryFollowUp;
143
+ /** `false` hides the dialog without losing its progress (e.g. while another unlock dialog is on top). */
144
+ open?: boolean;
145
+ onDone: () => void;
146
+ }
147
+
148
+ /**
149
+ * The steps after a recovery-code unlock, shown once the keys are already open:
150
+ *
151
+ * 1. Offer a new encryption password. Optional ("Skip") - unless this was the last code, where it's required before the
152
+ * code is used up (otherwise only a forgotten password would remain); then "Keep this code for now" closes without
153
+ * consuming anything.
154
+ * 2. Remove the used code. A failure is reported but never blocks anything - the keys are already open.
155
+ * 3. Say how many codes are left, nudging towards regenerating them at two or fewer.
156
+ *
157
+ * Mount it with a `key` per follow-up so each unlock starts from step 1.
158
+ */
159
+ export function RecoveryFollowUpModal({ followUp, open = true, onDone }: RecoveryFollowUpModalProps) {
160
+ const { mailboxUid, recoveryMethodId, remainingRecoveryCodes, expectedMasterKeyGeneration } = followUp;
161
+ const required = remainingRecoveryCodes === 0;
162
+ const [step, setStep] = useState<Step>("password");
163
+ const [newPassword, setNewPassword] = useState("");
164
+ const [confirmPassword, setConfirmPassword] = useState("");
165
+ const [error, setError] = useState<string | null>(null);
166
+ const [blocked, setBlocked] = useState<Blocked | null>(null);
167
+ const [busy, setBusy] = useState(false);
168
+ const [passwordSet, setPasswordSet] = useState(false);
169
+ const [consumeFailed, setConsumeFailed] = useState(false);
170
+
171
+ async function consume() {
172
+ let failed = !recoveryMethodId;
173
+ if (recoveryMethodId) {
174
+ try {
175
+ await consumeRecoveryCode(mailboxUid, recoveryMethodId);
176
+ } catch (err) {
177
+ // 404: already gone (e.g. consumed from another tab) - that's the outcome wanted.
178
+ failed = !(err instanceof ApiRequestError && err.status === 404);
179
+ }
180
+ }
181
+ setConsumeFailed(failed);
182
+ setStep("done");
183
+ }
184
+
185
+ async function handleSetPassword(e: FormEvent) {
186
+ e.preventDefault();
187
+ if (newPassword.length < MIN_PASSWORD_LENGTH) {
188
+ setError(`Password must be at least ${MIN_PASSWORD_LENGTH} characters.`);
189
+ return;
190
+ }
191
+ if (newPassword !== confirmPassword) {
192
+ setError("Passwords do not match.");
193
+ return;
194
+ }
195
+ setError(null);
196
+ setBusy(true);
197
+ try {
198
+ // Read now, not at unlock time: an idle timeout or a lock elsewhere may have destroyed the keys since.
199
+ const unlocked = getUnlockedKeys(mailboxUid);
200
+ if (!unlocked || unlocked.destroyed) {
201
+ throw new KeysLockedError();
202
+ }
203
+ // Before consuming - the unused code is the other unlock method that makes replacing safe.
204
+ await replacePasswordWrap(mailboxUid, unlocked, newPassword, expectedMasterKeyGeneration);
205
+ } catch (err) {
206
+ const failure = replaceFailure(err);
207
+ setBlocked(failure.blocked ?? null);
208
+ setError(failure.blocked ? null : failure.message);
209
+ setBusy(false);
210
+ return;
211
+ }
212
+ setNewPassword("");
213
+ setConfirmPassword("");
214
+ setPasswordSet(true);
215
+ await consume();
216
+ setBusy(false);
217
+ }
218
+
219
+ async function handleSkip() {
220
+ setError(null);
221
+ setBusy(true);
222
+ await consume();
223
+ setBusy(false);
224
+ }
225
+
226
+ const title = step === "done" ? "Recovery code used" : "Set a new encryption password";
227
+ const secondary = !blocked || !!blocked.allowSecondary;
228
+
229
+ function handleClose() {
230
+ if (busy) {
231
+ return;
232
+ }
233
+ // Closing the password step means the same as its secondary action - never a silent password change, and the
234
+ // last code is never consumed without a new password.
235
+ if (step === "password" && !required && secondary) {
236
+ void handleSkip();
237
+ return;
238
+ }
239
+ onDone();
240
+ }
241
+
242
+ return (
243
+ <Modal open={open} onClose={handleClose} title={title}>
244
+ {step === "password" ? (
245
+ <>
246
+ {required ? (
247
+ <p className="text-sm text-text-muted mb-4">
248
+ That was your last recovery code. Set a new encryption password before it&rsquo;s used up -
249
+ otherwise a password you&rsquo;ve forgotten would be the only way left to unlock this mailbox.
250
+ </p>
251
+ ) : (
252
+ <p className="text-sm text-text-muted mb-4">
253
+ Your mailbox is unlocked. If you&rsquo;ve forgotten your encryption password, set a new one now.
254
+ The recovery code you used will then be used up.
255
+ </p>
256
+ )}
257
+ {blocked ? (
258
+ <>
259
+ <Alert>{blocked.message}</Alert>
260
+ <div className="flex gap-2">
261
+ {blocked.reload && (
262
+ <Button type="button" className="!w-auto" onClick={() => window.location.reload()}>
263
+ Reload page
264
+ </Button>
265
+ )}
266
+ {!secondary && (
267
+ <Button type="button" variant="secondary" className="!w-auto" onClick={onDone}>
268
+ Close
269
+ </Button>
270
+ )}
271
+ </div>
272
+ </>
273
+ ) : (
274
+ <form onSubmit={handleSetPassword}>
275
+ {error && <Alert>{error}</Alert>}
276
+ <FormField label="New encryption password" htmlFor="recovery-new-password">
277
+ <input
278
+ id="recovery-new-password"
279
+ type="password"
280
+ className="w-full text-sm border border-border rounded-sm py-1.5 px-2 bg-surface"
281
+ value={newPassword}
282
+ onChange={(e) => setNewPassword(e.target.value)}
283
+ disabled={busy}
284
+ autoComplete="new-password"
285
+ autoFocus
286
+ />
287
+ </FormField>
288
+ <FormField label="Confirm new password" htmlFor="recovery-new-password-confirm">
289
+ <input
290
+ id="recovery-new-password-confirm"
291
+ type="password"
292
+ className="w-full text-sm border border-border rounded-sm py-1.5 px-2 bg-surface"
293
+ value={confirmPassword}
294
+ onChange={(e) => setConfirmPassword(e.target.value)}
295
+ disabled={busy}
296
+ autoComplete="new-password"
297
+ />
298
+ </FormField>
299
+ <Button type="submit" className="!w-auto" loading={busy} disabled={busy}>
300
+ Set password
301
+ </Button>
302
+ </form>
303
+ )}
304
+ {secondary && (
305
+ <div className="mt-2">
306
+ {required ? (
307
+ <Button type="button" variant="text" className="!w-auto" disabled={busy} onClick={onDone}>
308
+ Keep this code for now
309
+ </Button>
310
+ ) : (
311
+ <Button type="button" variant="text" className="!w-auto" disabled={busy} onClick={handleSkip}>
312
+ Skip
313
+ </Button>
314
+ )}
315
+ </div>
316
+ )}
317
+ </>
318
+ ) : (
319
+ <>
320
+ {passwordSet && <p className="text-sm mb-3">Your new encryption password is set.</p>}
321
+ {consumeFailed ? (
322
+ <p role="status" className="mb-3 py-2 px-3 rounded-sm text-sm bg-warning/15 text-text">
323
+ {CONSUME_FAILED_MESSAGE}
324
+ </p>
325
+ ) : (
326
+ <p className="text-sm mb-3">The recovery code you used has been used up and won&rsquo;t work again.</p>
327
+ )}
328
+ <p className="text-sm mb-3">
329
+ {remainingRecoveryCodes === 0
330
+ ? "You have no recovery codes left."
331
+ : `You have ${remainingRecoveryCodes} recovery ${remainingRecoveryCodes === 1 ? "code" : "codes"} left.`}
332
+ {remainingRecoveryCodes <= 2 && (
333
+ <>
334
+ {" "}
335
+ Generate a new set in{" "}
336
+ <a href={ENCRYPTION_SETTINGS_HREF} className="text-primary-dark hover:underline">
337
+ Settings &gt; Encryption
338
+ </a>{" "}
339
+ with Regenerate recovery codes.
340
+ </>
341
+ )}
342
+ </p>
343
+ <Button type="button" className="!w-auto" onClick={onDone}>
344
+ Done
345
+ </Button>
346
+ </>
347
+ )}
348
+ </Modal>
349
+ );
350
+ }