@rapidmx/web-client 0.5.0 → 0.7.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 (224) hide show
  1. package/README.md +88 -0
  2. package/apps/shared/components/admin/layout/AdminShell.tsx +25 -8
  3. package/apps/shared/components/admin/settings/BrandingForm.tsx +398 -385
  4. package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +119 -112
  5. package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +159 -152
  6. package/apps/shared/components/admin/settings/PluginsManager.tsx +1288 -1235
  7. package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +9 -1
  8. package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +288 -290
  9. package/apps/shared/components/admin/setup/SetupWizard.tsx +443 -416
  10. package/apps/shared/components/calendar/layout/CalendarShell.tsx +194 -192
  11. package/apps/shared/components/contacts/layout/ContactsShell.tsx +199 -197
  12. package/apps/shared/components/layout/AppShell.tsx +288 -270
  13. package/apps/shared/components/mail/ConversationList.tsx +225 -33
  14. package/apps/shared/components/mail/ConversationThreadPane.tsx +434 -216
  15. package/apps/shared/components/mail/MailListToolbar.tsx +265 -0
  16. package/apps/shared/components/mail/MailSelectionBar.tsx +222 -0
  17. package/apps/shared/components/mail/MenuButton.tsx +384 -0
  18. package/apps/shared/components/mail/MessageDetailPane.tsx +280 -215
  19. package/apps/shared/components/mail/MoveToFolderDialog.tsx +263 -0
  20. package/apps/shared/components/mail/compose/ComposeContext.tsx +29 -2
  21. package/apps/shared/components/mail/compose/ComposeWindow.tsx +1700 -1652
  22. package/apps/shared/components/mail/compose/RecipientInput.tsx +356 -0
  23. package/apps/shared/components/mail/compose/RichTextEditor.tsx +38 -3
  24. package/apps/shared/components/mail/compose/quotedBody.ts +100 -0
  25. package/apps/shared/components/mail/compose/recipients.ts +104 -0
  26. package/apps/shared/components/mail/labelMenu.tsx +278 -0
  27. package/apps/shared/components/mail/layout/MailShell.tsx +31 -4
  28. package/apps/shared/components/mail/listPreferences.ts +228 -0
  29. package/apps/shared/components/settings/layout/SettingsShell.tsx +23 -10
  30. package/apps/shared/components/tasks/layout/TasksShell.tsx +201 -199
  31. package/apps/shared/plugins/pluginNav.ts +73 -0
  32. package/apps/shared/search/localIndexRpcClient.ts +3 -1
  33. package/apps/shared/styles/app.css +28 -5
  34. package/apps/www/index.tsx +1854 -1314
  35. package/apps/www/messages/[uid].tsx +5 -4
  36. package/dist/apps/admin/_404.d.ts +2 -0
  37. package/dist/apps/admin/_500.d.ts +2 -0
  38. package/dist/apps/admin/_layout.d.ts +8 -0
  39. package/dist/apps/admin/audit-log/index.d.ts +11 -0
  40. package/dist/apps/admin/branding/index.d.ts +3 -0
  41. package/dist/apps/admin/data-requests/index.d.ts +3 -0
  42. package/dist/apps/admin/distribution-lists/[uid].d.ts +7 -0
  43. package/dist/apps/admin/distribution-lists/index.d.ts +3 -0
  44. package/dist/apps/admin/distribution-lists/new/index.d.ts +3 -0
  45. package/dist/apps/admin/domains/[uid].d.ts +7 -0
  46. package/dist/apps/admin/domains/index.d.ts +3 -0
  47. package/dist/apps/admin/domains/new/index.d.ts +3 -0
  48. package/dist/apps/admin/encryption-policy/index.d.ts +3 -0
  49. package/dist/apps/admin/escrow-scopes/[uid].d.ts +21 -0
  50. package/dist/apps/admin/escrow-scopes/index.d.ts +3 -0
  51. package/dist/apps/admin/escrow-scopes/new/index.d.ts +3 -0
  52. package/dist/apps/admin/index.d.ts +3 -0
  53. package/dist/apps/admin/ingest-queue/index.d.ts +4 -0
  54. package/dist/apps/admin/mailbox-policy/index.d.ts +3 -0
  55. package/dist/apps/admin/mailboxes/[uid].d.ts +7 -0
  56. package/dist/apps/admin/mailboxes/new/index.d.ts +3 -0
  57. package/dist/apps/admin/plugins/index.d.ts +3 -0
  58. package/dist/apps/admin/quarantine/index.d.ts +6 -0
  59. package/dist/apps/admin/retention-policy/index.d.ts +3 -0
  60. package/dist/apps/admin/setup/index.d.ts +3 -0
  61. package/dist/apps/admin/transport-rules/[uid].d.ts +7 -0
  62. package/dist/apps/admin/transport-rules/_transportRuleConfig.d.ts +21 -0
  63. package/dist/apps/admin/transport-rules/index.d.ts +3 -0
  64. package/dist/apps/admin/transport-rules/new/index.d.ts +3 -0
  65. package/dist/apps/escrow/_layout.d.ts +10 -0
  66. package/dist/apps/escrow/audit-log/index.d.ts +9 -0
  67. package/dist/apps/escrow/index.d.ts +3 -0
  68. package/dist/apps/escrow/matters/[uid].d.ts +7 -0
  69. package/dist/apps/escrow/matters/new/index.d.ts +3 -0
  70. package/dist/apps/shared/components/admin/distributionLists/MemberListCard.d.ts +17 -0
  71. package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.d.ts +32 -0
  72. package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +32 -0
  73. package/dist/apps/shared/components/admin/layout/AdminShell.js +12 -5
  74. package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.d.ts +12 -0
  75. package/dist/apps/shared/components/admin/mailboxes/MailboxTable.d.ts +6 -0
  76. package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.d.ts +19 -0
  77. package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.d.ts +12 -0
  78. package/dist/apps/shared/components/admin/settings/BrandingForm.d.ts +13 -0
  79. package/dist/apps/shared/components/admin/settings/BrandingForm.js +6 -5
  80. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.d.ts +12 -0
  81. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.d.ts +15 -0
  82. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +2 -2
  83. package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.d.ts +9 -0
  84. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.d.ts +19 -0
  85. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.d.ts +13 -0
  86. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +2 -2
  87. package/dist/apps/shared/components/admin/settings/PluginsManager.d.ts +11 -0
  88. package/dist/apps/shared/components/admin/settings/PluginsManager.js +33 -14
  89. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.d.ts +12 -0
  90. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +2 -2
  91. package/dist/apps/shared/components/admin/setup/EscrowSetupStep.d.ts +14 -0
  92. package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +1 -1
  93. package/dist/apps/shared/components/admin/setup/SetupWizard.d.ts +36 -0
  94. package/dist/apps/shared/components/admin/setup/SetupWizard.js +14 -10
  95. package/dist/apps/shared/components/admin/signOut.d.ts +23 -0
  96. package/dist/apps/shared/components/admin/usePagedList.d.ts +39 -0
  97. package/dist/apps/shared/components/calendar/CalendarListSidebar.d.ts +26 -0
  98. package/dist/apps/shared/components/calendar/EventModal.d.ts +46 -0
  99. package/dist/apps/shared/components/calendar/MonthView.d.ts +15 -0
  100. package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +20 -0
  101. package/dist/apps/shared/components/calendar/ResourcePicker.d.ts +19 -0
  102. package/dist/apps/shared/components/calendar/SplitDayView.d.ts +28 -0
  103. package/dist/apps/shared/components/calendar/TimeGridView.d.ts +17 -0
  104. package/dist/apps/shared/components/calendar/allDay.d.ts +51 -0
  105. package/dist/apps/shared/components/calendar/layout/CalendarShell.d.ts +40 -0
  106. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +2 -2
  107. package/dist/apps/shared/components/contacts/ContactDetailPane.d.ts +23 -0
  108. package/dist/apps/shared/components/contacts/ContactForm.d.ts +20 -0
  109. package/dist/apps/shared/components/contacts/ContactsSidebar.d.ts +40 -0
  110. package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +25 -0
  111. package/dist/apps/shared/components/contacts/KeyChangeReview.d.ts +40 -0
  112. package/dist/apps/shared/components/contacts/contactKeys.d.ts +29 -0
  113. package/dist/apps/shared/components/contacts/layout/ContactsShell.d.ts +21 -0
  114. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +2 -2
  115. package/dist/apps/shared/components/escrow/layout/EscrowShell.d.ts +25 -0
  116. package/dist/apps/shared/components/forms/StringListField.d.ts +22 -0
  117. package/dist/apps/shared/components/layout/AppShell.d.ts +49 -0
  118. package/dist/apps/shared/components/layout/AppShell.js +15 -13
  119. package/dist/apps/shared/components/layout/BrandingChrome.d.ts +18 -0
  120. package/dist/apps/shared/components/layout/KeyEnrollmentGate.d.ts +51 -0
  121. package/dist/apps/shared/components/layout/MailboxProvisioning.d.ts +13 -0
  122. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.d.ts +66 -0
  123. package/dist/apps/shared/components/layout/UnlockPromptProvider.d.ts +45 -0
  124. package/dist/apps/shared/components/layout/UserMenu.d.ts +23 -0
  125. package/dist/apps/shared/components/mail/ConversationList.d.ts +47 -0
  126. package/dist/apps/shared/components/mail/ConversationList.js +84 -10
  127. package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +62 -0
  128. package/dist/apps/shared/components/mail/ConversationThreadPane.js +217 -60
  129. package/dist/apps/shared/components/mail/MailListToolbar.d.ts +55 -0
  130. package/dist/apps/shared/components/mail/MailListToolbar.js +149 -0
  131. package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +59 -0
  132. package/dist/apps/shared/components/mail/MailSelectionBar.js +48 -0
  133. package/dist/apps/shared/components/mail/MenuButton.d.ts +71 -0
  134. package/dist/apps/shared/components/mail/MenuButton.js +211 -0
  135. package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +101 -0
  136. package/dist/apps/shared/components/mail/MessageDetailPane.js +126 -129
  137. package/dist/apps/shared/components/mail/MoveToFolderDialog.d.ts +57 -0
  138. package/dist/apps/shared/components/mail/MoveToFolderDialog.js +138 -0
  139. package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +73 -0
  140. package/dist/apps/shared/components/mail/compose/ComposeContext.js +3 -1
  141. package/dist/apps/shared/components/mail/compose/ComposeToolbar.d.ts +15 -0
  142. package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +37 -0
  143. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +52 -20
  144. package/dist/apps/shared/components/mail/compose/EmojiPicker.d.ts +14 -0
  145. package/dist/apps/shared/components/mail/compose/GifPicker.d.ts +13 -0
  146. package/dist/apps/shared/components/mail/compose/RecipientInput.d.ts +36 -0
  147. package/dist/apps/shared/components/mail/compose/RecipientInput.js +203 -0
  148. package/dist/apps/shared/components/mail/compose/RichTextEditor.d.ts +43 -0
  149. package/dist/apps/shared/components/mail/compose/RichTextEditor.js +21 -3
  150. package/dist/apps/shared/components/mail/compose/ScheduleSendPicker.d.ts +16 -0
  151. package/dist/apps/shared/components/mail/compose/composeFlushRegistry.d.ts +27 -0
  152. package/dist/apps/shared/components/mail/compose/quotedBody.d.ts +37 -0
  153. package/dist/apps/shared/components/mail/compose/quotedBody.js +85 -0
  154. package/dist/apps/shared/components/mail/compose/recipients.d.ts +24 -0
  155. package/dist/apps/shared/components/mail/compose/recipients.js +87 -0
  156. package/dist/apps/shared/components/mail/labelMenu.d.ts +97 -0
  157. package/dist/apps/shared/components/mail/labelMenu.js +134 -0
  158. package/dist/apps/shared/components/mail/layout/MailShell.d.ts +65 -0
  159. package/dist/apps/shared/components/mail/layout/MailShell.js +17 -5
  160. package/dist/apps/shared/components/mail/listPreferences.d.ts +101 -0
  161. package/dist/apps/shared/components/mail/listPreferences.js +186 -0
  162. package/dist/apps/shared/components/mail/pinnedSigners.d.ts +33 -0
  163. package/dist/apps/shared/components/mail/verificationSeals.d.ts +22 -0
  164. package/dist/apps/shared/components/mail/writableMailboxes.d.ts +15 -0
  165. package/dist/apps/shared/components/rules/RuleBuilder.d.ts +70 -0
  166. package/dist/apps/shared/components/settings/layout/SettingsShell.d.ts +41 -0
  167. package/dist/apps/shared/components/settings/layout/SettingsShell.js +19 -10
  168. package/dist/apps/shared/components/tasks/TasksSidebar.d.ts +41 -0
  169. package/dist/apps/shared/components/tasks/TasksToolbar.d.ts +14 -0
  170. package/dist/apps/shared/components/tasks/layout/TasksShell.d.ts +24 -0
  171. package/dist/apps/shared/components/tasks/layout/TasksShell.js +2 -2
  172. package/dist/apps/shared/mail/findWellKnownFolderUid.d.ts +5 -0
  173. package/dist/apps/shared/mail/listAllPages.d.ts +17 -0
  174. package/dist/apps/shared/plugins/pluginNav.d.ts +39 -0
  175. package/dist/apps/shared/plugins/pluginNav.js +33 -0
  176. package/dist/apps/shared/search/LocalIndexLifecycle.d.ts +13 -0
  177. package/dist/apps/shared/search/localIndexBlockCipher.d.ts +36 -0
  178. package/dist/apps/shared/search/localIndexBuilder.d.ts +85 -0
  179. package/dist/apps/shared/search/localIndexKey.d.ts +4 -0
  180. package/dist/apps/shared/search/localIndexRpcClient.d.ts +71 -0
  181. package/dist/apps/shared/search/localIndexRpcClient.js +3 -1
  182. package/dist/apps/shared/search/localIndexSchema.d.ts +111 -0
  183. package/dist/apps/shared/search/localIndexSizePreference.d.ts +27 -0
  184. package/dist/apps/shared/search/localIndexStorage.d.ts +28 -0
  185. package/dist/apps/shared/search/localIndexVFS.d.ts +101 -0
  186. package/dist/apps/shared/search/localIndexWorker.d.ts +145 -0
  187. package/dist/apps/shared/search/searchTier2.d.ts +30 -0
  188. package/dist/apps/shared/styles/app.css +28 -5
  189. package/dist/apps/www/_404.d.ts +2 -0
  190. package/dist/apps/www/_500.d.ts +2 -0
  191. package/dist/apps/www/_layout.d.ts +14 -0
  192. package/dist/apps/www/calendar/index.d.ts +3 -0
  193. package/dist/apps/www/contacts/[uid].d.ts +13 -0
  194. package/dist/apps/www/contacts/index.d.ts +3 -0
  195. package/dist/apps/www/index.d.ts +3 -0
  196. package/dist/apps/www/index.js +506 -112
  197. package/dist/apps/www/messages/[uid].d.ts +11 -0
  198. package/dist/apps/www/messages/[uid].js +2 -3
  199. package/dist/apps/www/settings/auto-reply/index.d.ts +4 -0
  200. package/dist/apps/www/settings/encryption/index.d.ts +7 -0
  201. package/dist/apps/www/settings/filters/[uid].d.ts +8 -0
  202. package/dist/apps/www/settings/filters/_mailFilterRuleConfig.d.ts +11 -0
  203. package/dist/apps/www/settings/filters/index.d.ts +4 -0
  204. package/dist/apps/www/settings/filters/new/index.d.ts +4 -0
  205. package/dist/apps/www/settings/labels/index.d.ts +4 -0
  206. package/dist/apps/www/settings/privacy/index.d.ts +4 -0
  207. package/dist/apps/www/settings/read-receipts/index.d.ts +4 -0
  208. package/dist/apps/www/settings/sharing/index.d.ts +4 -0
  209. package/dist/apps/www/settings/signatures/[uid].d.ts +8 -0
  210. package/dist/apps/www/settings/signatures/index.d.ts +4 -0
  211. package/dist/apps/www/settings/signatures/new/index.d.ts +4 -0
  212. package/dist/apps/www/settings/signatures/signatureDefaults.d.ts +10 -0
  213. package/dist/apps/www/tasks/index.d.ts +3 -0
  214. package/package.json +3 -3
  215. package/apps/shared/components/booking/AvailabilityEditor.tsx +0 -118
  216. package/apps/www/settings/booking-types/[uid].tsx +0 -306
  217. package/apps/www/settings/booking-types/index.tsx +0 -98
  218. package/apps/www/settings/booking-types/new/index.tsx +0 -212
  219. package/apps/www/settings/focused-inbox/index.tsx +0 -150
  220. package/dist/apps/shared/components/booking/AvailabilityEditor.js +0 -45
  221. package/dist/apps/www/settings/booking-types/[uid].js +0 -134
  222. package/dist/apps/www/settings/booking-types/index.js +0 -29
  223. package/dist/apps/www/settings/booking-types/new/index.js +0 -86
  224. package/dist/apps/www/settings/focused-inbox/index.js +0 -71
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ import { MailShellProps } from "../../shared/components/mail/layout/MailShell.js";
3
+ /**
4
+ * Only reached on mobile (below the `md` breakpoint) — desktop's `apps/www/index.tsx` keeps its existing
5
+ * inline reading pane and never navigates here; see that file's `handleSelect`.
6
+ */
7
+ export default function MessageDetailPage(props: MailShellProps & {
8
+ params: {
9
+ uid: string;
10
+ };
11
+ }): React.JSX.Element;
@@ -19,7 +19,7 @@ export default function MessageDetailPage(props) {
19
19
  return (_jsx(MailShell, { ...props, children: _jsx(MessageDetailContent, { uid: props.params.uid }) }));
20
20
  }
21
21
  function MessageDetailContent({ uid }) {
22
- const { mailboxFolders, mailboxUid } = useMailShell();
22
+ const { mailboxFolders, mailboxUid, onFolderCreated } = useMailShell();
23
23
  const [message, setMessage] = useState(null);
24
24
  const [loading, setLoading] = useState(true);
25
25
  const [error, setError] = useState(null);
@@ -67,7 +67,6 @@ function MessageDetailContent({ uid }) {
67
67
  const backHref = `/?mailboxUid=${encodeURIComponent(message.mailboxUid)}&folderUid=${encodeURIComponent(message.folderUid)}`;
68
68
  const isSentItems = folders.find((f) => f.uid === message.folderUid)?.type === "sent_items";
69
69
  const isOutbox = folders.find((f) => f.uid === message.folderUid)?.type === "outbox";
70
- const isInbox = folders.find((f) => f.uid === message.folderUid)?.type === "inbox";
71
70
  const draftsFolderUid = folders.find((f) => f.type === "drafts")?.uid;
72
- return (_jsx(MessageDetailPane, { message: message, attachments: attachments, backHref: backHref, isSentItems: isSentItems, onRecalled: setMessage, isOutbox: isOutbox, isInbox: isInbox, onClassified: setMessage, onReceiptHandled: setMessage, draftsFolderUid: draftsFolderUid, onScheduledSendCanceled: setMessage, onArchived: setMessage, labels: labels, onLabelsChanged: setMessage }));
71
+ return (_jsx(MessageDetailPane, { message: message, attachments: attachments, backHref: backHref, isSentItems: isSentItems, onRecalled: setMessage, isOutbox: isOutbox, onReceiptHandled: setMessage, draftsFolderUid: draftsFolderUid, folders: folders, onMoved: setMessage, onFolderCreated: onFolderCreated, onScheduledSendCanceled: setMessage, onArchived: setMessage, labels: labels, onLabelsChanged: setMessage, onLabelCreated: (label) => setLabels((prev) => [...prev, label]) }));
73
72
  }
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
+ export type SettingsAutoReplyPageProps = Omit<SettingsShellProps, "active">;
4
+ export default function SettingsAutoReplyPage(props: SettingsAutoReplyPageProps): React.JSX.Element;
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
+ /** Mirrors restapi's `BaseKeyVaultRoute` `MAX_MASTER_KEY_WRAPS` - `addMasterKeyWrap()` refuses a vault
4
+ * already holding this many wraps (escrow included). */
5
+ export declare const MAX_MASTER_KEY_WRAPS = 20;
6
+ export type SettingsEncryptionPageProps = Omit<SettingsShellProps, "active">;
7
+ export default function SettingsEncryptionPage(props: SettingsEncryptionPageProps): React.JSX.Element;
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
+ export type MailFilterDetailPageProps = Omit<SettingsShellProps, "active"> & {
4
+ params: {
5
+ uid: string;
6
+ };
7
+ };
8
+ export default function MailFilterDetailPage(props: MailFilterDetailPageProps): React.JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { Folder } from "@rapidmx/react-shared/mail/mailApi.js";
2
+ import { MailFilterAction } from "@rapidmx/react-shared/mail/mailFilterRulesApi.js";
3
+ import { ActionTypeDef, ConditionFieldDef } from "../../../shared/components/rules/RuleBuilder.js";
4
+ export declare const MAIL_FILTER_CONDITION_FIELDS: ConditionFieldDef[];
5
+ /**
6
+ * Builds the mail-filter action-type registry for `RuleBuilder`, closing over `folders` so the
7
+ * move/copy-to-folder actions can render a real folder picker. `RuleBuilder`'s own `render()` contract
8
+ * is synchronous, so this resolves `folders` once up front (the caller already loads them for the page
9
+ * itself) rather than each action row fetching independently.
10
+ */
11
+ export declare function buildMailFilterActionTypes(folders: Folder[]): ActionTypeDef<MailFilterAction>[];
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
+ export type SettingsFiltersPageProps = Omit<SettingsShellProps, "active">;
4
+ export default function SettingsFiltersPage(props: SettingsFiltersPageProps): React.JSX.Element;
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../../shared/components/settings/layout/SettingsShell.js";
3
+ export type NewMailFilterPageProps = Omit<SettingsShellProps, "active">;
4
+ export default function NewMailFilterPage(props: NewMailFilterPageProps): React.JSX.Element;
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
+ export type SettingsLabelsPageProps = Omit<SettingsShellProps, "active">;
4
+ export default function SettingsLabelsPage(props: SettingsLabelsPageProps): React.JSX.Element;
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
+ export type SettingsPrivacyPageProps = Omit<SettingsShellProps, "active">;
4
+ export default function SettingsPrivacyPage(props: SettingsPrivacyPageProps): React.JSX.Element;
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
+ export type SettingsReadReceiptsPageProps = Omit<SettingsShellProps, "active">;
4
+ export default function SettingsReadReceiptsPage(props: SettingsReadReceiptsPageProps): React.JSX.Element;
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
+ export type SettingsSharingPageProps = Omit<SettingsShellProps, "active">;
4
+ export default function SettingsSharingPage(props: SettingsSharingPageProps): React.JSX.Element;
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
+ export type SignatureDetailPageProps = Omit<SettingsShellProps, "active"> & {
4
+ params: {
5
+ uid: string;
6
+ };
7
+ };
8
+ export default function SignatureDetailPage(props: SignatureDetailPageProps): React.JSX.Element;
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
+ export type SettingsSignaturesPageProps = Omit<SettingsShellProps, "active">;
4
+ export default function SettingsSignaturesPage(props: SettingsSignaturesPageProps): React.JSX.Element;
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import { SettingsShellProps } from "../../../../shared/components/settings/layout/SettingsShell.js";
3
+ export type NewSignaturePageProps = Omit<SettingsShellProps, "active">;
4
+ export default function NewSignaturePage(props: NewSignaturePageProps): React.JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { MailSignature } from "@rapidmx/react-shared/mail/mailSignaturesApi.js";
2
+ /**
3
+ * `MailSignature.isDefaultForNewMessages`/`isDefaultForReplyForward` are each meant to hold on at most
4
+ * one signature per mailbox — enforced by convention, not a database constraint (see
5
+ * `mailSignaturesApi.ts`'s own doc comment, quoting restapi's). Before saving a signature with one of
6
+ * these flags newly turned on, this turns the flag off on whichever *other* signature in `signatures`
7
+ * currently has it — the "the composing client toggles the previous default off" responsibility that
8
+ * convention assigns to a caller like the New/Edit signature forms.
9
+ */
10
+ export declare function clearPreviousDefaults(signatures: MailSignature[], savingUid: string | undefined, isDefaultForNewMessages: boolean, isDefaultForReplyForward: boolean): Promise<void>;
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ import { TasksShellProps } from "../../shared/components/tasks/layout/TasksShell.js";
3
+ export default function TasksPage(props: TasksShellProps): React.JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rapidmx/web-client",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "RapidMX's webmail and admin console React UI for web-based clients.",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/rapidmx/web-client",
@@ -17,7 +17,7 @@
17
17
  "./shared/styles/app.css": "./apps/shared/styles/app.css"
18
18
  },
19
19
  "scripts": {
20
- "build": "rimraf dist && tsc -p tsconfig.json && shx mkdir -p dist/apps/shared/styles && shx cp apps/shared/styles/app.css dist/apps/shared/styles/app.css",
20
+ "build": "rimraf dist && tsc -p tsconfig.json && shx mkdir -p dist/apps/shared/styles && shx cp apps/shared/styles/app.css dist/apps/shared/styles/app.css && node scripts/checkDistReferences.mjs",
21
21
  "lint": "eslint ./apps ./test",
22
22
  "test": "vitest run --coverage",
23
23
  "test:watch": "vitest --watch --coverage",
@@ -39,7 +39,7 @@
39
39
  "@dnd-kit/core": "^6.3.1",
40
40
  "@journeyapps/wa-sqlite": "^2.0.4",
41
41
  "@peculiar/x509": "^2.1.0",
42
- "@rapidmx/react-shared": "patch:@rapidmx/react-shared@npm%3A0.4.0#~/.yarn/patches/@rapidmx-react-shared-npm-0.4.0-e713beecf2.patch",
42
+ "@rapidmx/react-shared": "^0.7.0",
43
43
  "@tiptap/core": "^3.31.3",
44
44
  "@tiptap/extension-highlight": "^3.31.3",
45
45
  "@tiptap/extension-image": "^3.31.3",
@@ -1,118 +0,0 @@
1
- ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2026 Jean-Philippe Steinmetz
3
- // SPDX-License-Identifier: MPL-2.0
4
- ///////////////////////////////////////////////////////////////////////////////
5
- import React, { useState } from "react";
6
- import { BookingAvailabilityWindow } from "@rapidmx/react-shared/booking/bookingApi.js";
7
- import Button from "@rapidmx/react-shared/components/buttons/Button.js";
8
-
9
- const DAY_LABELS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
10
- const INPUT_CLASS =
11
- "text-sm py-2 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
12
-
13
- function minutesToTimeValue(minutes: number): string {
14
- const h = Math.floor(minutes / 60)
15
- .toString()
16
- .padStart(2, "0");
17
- const m = (minutes % 60).toString().padStart(2, "0");
18
- return `${h}:${m}`;
19
- }
20
-
21
- function timeValueToMinutes(value: string): number {
22
- const [h, m] = value.split(":").map(Number);
23
- return h * 60 + m;
24
- }
25
-
26
- export interface AvailabilityEditorProps {
27
- value: BookingAvailabilityWindow[];
28
- onChange: (value: BookingAvailabilityWindow[]) => void;
29
- }
30
-
31
- /**
32
- * Adds/removes `BookingType.availability` weekly windows — deliberately does not cover `dateOverrides`
33
- * (per-date blackouts/exceptions), a separate, less commonly needed escape hatch left for a future pass;
34
- * `BookingUtils.generateCandidateSlots()` already handles an empty `dateOverrides` array gracefully.
35
- */
36
- export default function AvailabilityEditor({ value, onChange }: AvailabilityEditorProps) {
37
- const [dayOfWeek, setDayOfWeek] = useState(1);
38
- const [startTime, setStartTime] = useState("09:00");
39
- const [endTime, setEndTime] = useState("17:00");
40
- const [error, setError] = useState<string | null>(null);
41
-
42
- function handleAdd() {
43
- const startMinute = timeValueToMinutes(startTime);
44
- const endMinute = timeValueToMinutes(endTime);
45
- if (startMinute >= endMinute) {
46
- setError("Start time must be before end time.");
47
- return;
48
- }
49
- setError(null);
50
- onChange([...value, { dayOfWeek, startMinute, endMinute }]);
51
- }
52
-
53
- function handleRemove(index: number) {
54
- onChange(value.filter((_, i) => i !== index));
55
- }
56
-
57
- return (
58
- <div className="flex flex-col gap-3">
59
- {error && <p className="text-sm text-danger">{error}</p>}
60
- {value.length === 0 ? (
61
- <p className="text-sm text-text-muted">No availability windows yet — add one below.</p>
62
- ) : (
63
- <ul className="flex flex-col gap-2">
64
- {value.map((window, index) => (
65
- <li
66
- key={index}
67
- className="flex items-center justify-between gap-3 py-2 px-3 border border-border rounded-sm text-sm"
68
- >
69
- <span>
70
- {DAY_LABELS[window.dayOfWeek]} {minutesToTimeValue(window.startMinute)}&ndash;
71
- {minutesToTimeValue(window.endMinute)}
72
- </span>
73
- <button
74
- type="button"
75
- onClick={() => handleRemove(index)}
76
- className="text-sm text-danger hover:underline"
77
- >
78
- Remove
79
- </button>
80
- </li>
81
- ))}
82
- </ul>
83
- )}
84
- <div className="flex flex-wrap items-center gap-2">
85
- <select
86
- aria-label="Day of week"
87
- value={dayOfWeek}
88
- onChange={(e) => setDayOfWeek(Number(e.target.value))}
89
- className={INPUT_CLASS}
90
- >
91
- {DAY_LABELS.map((label, i) => (
92
- <option key={label} value={i}>
93
- {label}
94
- </option>
95
- ))}
96
- </select>
97
- <input
98
- type="time"
99
- aria-label="Start time"
100
- value={startTime}
101
- onChange={(e) => setStartTime(e.target.value)}
102
- className={INPUT_CLASS}
103
- />
104
- <span className="text-sm text-text-muted">to</span>
105
- <input
106
- type="time"
107
- aria-label="End time"
108
- value={endTime}
109
- onChange={(e) => setEndTime(e.target.value)}
110
- className={INPUT_CLASS}
111
- />
112
- <Button type="button" variant="secondary" className="!w-auto" onClick={handleAdd}>
113
- Add window
114
- </Button>
115
- </div>
116
- </div>
117
- );
118
- }
@@ -1,306 +0,0 @@
1
- ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2026 Jean-Philippe Steinmetz
3
- // SPDX-License-Identifier: MPL-2.0
4
- ///////////////////////////////////////////////////////////////////////////////
5
- import React, { FormEvent, useEffect, useState } from "react";
6
- import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
7
- import {
8
- BookingAvailabilityWindow,
9
- BookingType,
10
- deleteBookingType,
11
- getBookingType,
12
- updateBookingType,
13
- } from "@rapidmx/react-shared/booking/bookingApi.js";
14
- import SettingsShell, { SettingsShellProps, useSettingsShell } from "../../../shared/components/settings/layout/SettingsShell.js";
15
- import AvailabilityEditor from "../../../shared/components/booking/AvailabilityEditor.js";
16
- import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
17
- import Button from "@rapidmx/react-shared/components/buttons/Button.js";
18
- import FormField from "@rapidmx/react-shared/components/forms/FormField.js";
19
- import Modal from "@rapidmx/react-shared/components/overlays/Modal.js";
20
-
21
- const INPUT_CLASS =
22
- "w-full text-sm py-2.5 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
23
-
24
- export type BookingTypeDetailPageProps = Omit<SettingsShellProps, "active"> & { params: { uid: string } };
25
-
26
- export default function BookingTypeDetailPage(props: BookingTypeDetailPageProps) {
27
- return (
28
- <SettingsShell {...props} active="booking-types">
29
- <BookingTypeDetailContent uid={props.params.uid} />
30
- </SettingsShell>
31
- );
32
- }
33
-
34
- function BookingTypeDetailContent({ uid }: { uid: string }) {
35
- const { mailboxUid } = useSettingsShell();
36
- const [bookingType, setBookingType] = useState<BookingType | null>(null);
37
- const [name, setName] = useState("");
38
- const [description, setDescription] = useState("");
39
- const [hostDisplayName, setHostDisplayName] = useState("");
40
- const [durationMinutes, setDurationMinutes] = useState(30);
41
- const [timezone, setTimezone] = useState("");
42
- const [availability, setAvailability] = useState<BookingAvailabilityWindow[]>([]);
43
- const [minimumNoticeMinutes, setMinimumNoticeMinutes] = useState(60);
44
- const [bookingWindowDays, setBookingWindowDays] = useState(30);
45
- const [requiresApproval, setRequiresApproval] = useState(false);
46
- const [enabled, setEnabled] = useState(true);
47
- const [loading, setLoading] = useState(true);
48
- // Split so a failed save keeps the form (and the user's edits) on screen - only a failed *load* has
49
- // nothing to show but the error.
50
- const [loadError, setLoadError] = useState<string | null>(null);
51
- const [saveError, setSaveError] = useState<string | null>(null);
52
- const [saving, setSaving] = useState(false);
53
- const [saved, setSaved] = useState(false);
54
- const [copied, setCopied] = useState(false);
55
- const [confirmingDelete, setConfirmingDelete] = useState(false);
56
- const [deleting, setDeleting] = useState(false);
57
- const [deleteError, setDeleteError] = useState<string | null>(null);
58
-
59
- useEffect(() => {
60
- setLoading(true);
61
- setLoadError(null);
62
- getBookingType(uid)
63
- .then((bt) => {
64
- setBookingType(bt);
65
- setName(bt.name);
66
- setDescription(bt.description ?? "");
67
- setHostDisplayName(bt.hostDisplayName);
68
- setDurationMinutes(bt.durationMinutes);
69
- setTimezone(bt.timezone);
70
- setAvailability(bt.availability);
71
- setMinimumNoticeMinutes(bt.minimumNoticeMinutes);
72
- setBookingWindowDays(bt.bookingWindowDays);
73
- setRequiresApproval(bt.requiresApproval);
74
- setEnabled(bt.enabled);
75
- })
76
- .catch((err) => setLoadError(err instanceof ApiRequestError ? err.message : "Could not load this booking link."))
77
- .finally(() => setLoading(false));
78
- }, [uid]);
79
-
80
- async function handleSubmit(e: FormEvent) {
81
- e.preventDefault();
82
- setSaveError(null);
83
- setSaved(false);
84
- setSaving(true);
85
- try {
86
- const updated = await updateBookingType({
87
- uid: bookingType!.uid,
88
- version: bookingType!.version,
89
- name,
90
- // `null` (not omitted) clears a saved description - an omitted field is left unchanged by the
91
- // server's partial update. `UpdateBookingTypeInput` doesn't declare `null` yet, hence the cast.
92
- description: description.trim() || (null as unknown as undefined),
93
- hostDisplayName,
94
- durationMinutes,
95
- timezone,
96
- availability,
97
- minimumNoticeMinutes,
98
- bookingWindowDays,
99
- requiresApproval,
100
- enabled,
101
- });
102
- setBookingType(updated);
103
- setSaved(true);
104
- } catch (err) {
105
- setSaveError(err instanceof ApiRequestError ? err.message : "Could not save this booking link.");
106
- } finally {
107
- setSaving(false);
108
- }
109
- }
110
-
111
- async function handleCopy(value: string) {
112
- try {
113
- await navigator.clipboard.writeText(value);
114
- setCopied(true);
115
- setTimeout(() => setCopied(false), 2000);
116
- } catch {
117
- // Clipboard access can be denied by the browser — the value is still selectable/copyable by hand.
118
- }
119
- }
120
-
121
- async function handleDelete() {
122
- setDeleting(true);
123
- setDeleteError(null);
124
- try {
125
- await deleteBookingType(bookingType!.uid, bookingType!.version);
126
- window.location.href = `/settings/booking-types?mailboxUid=${encodeURIComponent(mailboxUid!)}`;
127
- } catch (err) {
128
- setDeleteError(err instanceof ApiRequestError ? err.message : "Could not delete this booking link.");
129
- setDeleting(false);
130
- }
131
- }
132
-
133
- if (loading) {
134
- return <p className="p-6 text-sm text-text-muted">Loading&hellip;</p>;
135
- }
136
- if (loadError || !bookingType) {
137
- // `loadError` is always set whenever `bookingType` is falsy here: the load effect above destructures
138
- // every field off the resolved value directly (`bt.name`, `bt.hostDisplayName`, ...), so a
139
- // successful-but-empty response throws into `.catch()` — which sets `loadError` — before this
140
- // component ever renders past the `loading` guard above. `!bookingType` alone (with `loadError` still
141
- // `null`) is therefore unreachable, unlike e.g. `messages/[uid].tsx`'s identical-looking check,
142
- // which stores its fetched value whole rather than destructuring it.
143
- return (
144
- <div className="p-6">
145
- <Alert>{loadError!}</Alert>
146
- </div>
147
- );
148
- }
149
-
150
- // `bookingType` only ever becomes non-null via the client-only fetch above, so by the time this line
151
- // runs `window` is always defined — the `!bookingType` early return just above covers every real SSR
152
- // pass, where `bookingType` is still `null`.
153
- const publicUrl = `${window.location.origin}/book/${encodeURIComponent(bookingType.slug)}`;
154
-
155
- return (
156
- <div className="flex-1 min-w-0 overflow-y-auto p-6">
157
- <div className="max-w-2xl">
158
- <div className="flex items-start justify-between gap-4 mb-1">
159
- <div>
160
- <a
161
- href={`/settings/booking-types?mailboxUid=${encodeURIComponent(mailboxUid!)}`}
162
- className="text-sm text-primary-dark hover:underline"
163
- >
164
- &larr; All booking links
165
- </a>
166
- <h1 className="text-xl font-bold tracking-tight mt-1">{bookingType.name}</h1>
167
- </div>
168
- <Button
169
- type="button"
170
- variant="secondary"
171
- className="!w-auto shrink-0 !border-danger !text-danger hover:!border-danger hover:!text-danger"
172
- onClick={() => setConfirmingDelete(true)}
173
- >
174
- Delete
175
- </Button>
176
- </div>
177
-
178
- <div className="flex items-center gap-2 mb-5">
179
- <code className="flex-1 text-xs bg-surface-alt border border-border rounded-sm py-2 px-3 overflow-x-auto whitespace-nowrap">
180
- {publicUrl}
181
- </code>
182
- <Button type="button" variant="secondary" className="!w-auto shrink-0" onClick={() => handleCopy(publicUrl)}>
183
- {copied ? "Copied" : "Copy"}
184
- </Button>
185
- </div>
186
-
187
- {saveError && <Alert>{saveError}</Alert>}
188
- {saved && !saveError && <div className="mb-4 text-sm text-success font-medium">Saved.</div>}
189
-
190
- <form onSubmit={handleSubmit} className="flex flex-col gap-1">
191
- <label className="flex items-center gap-2 text-sm mb-3">
192
- <input type="checkbox" checked={enabled} onChange={(e) => setEnabled(e.target.checked)} />
193
- Enabled (publicly bookable)
194
- </label>
195
- <FormField label="Name" htmlFor="name">
196
- <input id="name" type="text" className={INPUT_CLASS} value={name} onChange={(e) => setName(e.target.value)} />
197
- </FormField>
198
- <FormField label="Description (optional)" htmlFor="description">
199
- <textarea
200
- id="description"
201
- className={INPUT_CLASS}
202
- rows={2}
203
- value={description}
204
- onChange={(e) => setDescription(e.target.value)}
205
- />
206
- </FormField>
207
- <FormField label="Host name shown to visitors" htmlFor="hostDisplayName">
208
- <input
209
- id="hostDisplayName"
210
- type="text"
211
- className={INPUT_CLASS}
212
- value={hostDisplayName}
213
- onChange={(e) => setHostDisplayName(e.target.value)}
214
- />
215
- </FormField>
216
- <div className="grid grid-cols-2 gap-3">
217
- <FormField label="Duration (minutes)" htmlFor="durationMinutes">
218
- <input
219
- id="durationMinutes"
220
- type="number"
221
- min={1}
222
- className={INPUT_CLASS}
223
- value={durationMinutes}
224
- onChange={(e) => setDurationMinutes(Number(e.target.value))}
225
- />
226
- </FormField>
227
- <FormField label="Timezone" htmlFor="timezone">
228
- <input
229
- id="timezone"
230
- type="text"
231
- className={INPUT_CLASS}
232
- value={timezone}
233
- onChange={(e) => setTimezone(e.target.value)}
234
- />
235
- </FormField>
236
- </div>
237
- <div className="grid grid-cols-2 gap-3">
238
- <FormField label="Minimum notice (minutes)" htmlFor="minimumNoticeMinutes">
239
- <input
240
- id="minimumNoticeMinutes"
241
- type="number"
242
- min={0}
243
- className={INPUT_CLASS}
244
- value={minimumNoticeMinutes}
245
- onChange={(e) => setMinimumNoticeMinutes(Number(e.target.value))}
246
- />
247
- </FormField>
248
- <FormField label="Booking window (days ahead)" htmlFor="bookingWindowDays">
249
- <input
250
- id="bookingWindowDays"
251
- type="number"
252
- min={1}
253
- className={INPUT_CLASS}
254
- value={bookingWindowDays}
255
- onChange={(e) => setBookingWindowDays(Number(e.target.value))}
256
- />
257
- </FormField>
258
- </div>
259
- <label className="flex items-center gap-2 text-sm my-3">
260
- <input type="checkbox" checked={requiresApproval} onChange={(e) => setRequiresApproval(e.target.checked)} />
261
- Require my approval before confirming a booking
262
- </label>
263
-
264
- <div className="mb-4">
265
- <span className="block text-sm font-semibold mb-1.5 text-text">Weekly availability</span>
266
- <AvailabilityEditor value={availability} onChange={setAvailability} />
267
- </div>
268
-
269
- <div>
270
- <Button type="submit" loading={saving} disabled={saving} className="!w-auto">
271
- Save
272
- </Button>
273
- </div>
274
- </form>
275
-
276
- <Modal open={confirmingDelete} onClose={() => setConfirmingDelete(false)} title="Delete booking link">
277
- <p className="text-sm mb-5">
278
- Are you sure you want to delete <strong>{bookingType.name}</strong>? Its public link will stop
279
- working immediately. This cannot be undone.
280
- </p>
281
- {deleteError && <Alert>{deleteError}</Alert>}
282
- <div className="flex gap-3 justify-end mt-5">
283
- <Button
284
- type="button"
285
- variant="secondary"
286
- className="!w-auto"
287
- disabled={deleting}
288
- onClick={() => setConfirmingDelete(false)}
289
- >
290
- Cancel
291
- </Button>
292
- <Button
293
- type="button"
294
- className="!w-auto !bg-none !bg-danger !border-danger hover:!bg-danger"
295
- loading={deleting}
296
- disabled={deleting}
297
- onClick={handleDelete}
298
- >
299
- Delete
300
- </Button>
301
- </div>
302
- </Modal>
303
- </div>
304
- </div>
305
- );
306
- }