@rapidmx/web-client 0.8.0 → 0.10.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 (247) hide show
  1. package/README.md +192 -88
  2. package/apps/shared/auth/accountUrl.ts +9 -0
  3. package/apps/shared/auth/adminAccess.ts +99 -0
  4. package/apps/shared/components/admin/elevation.ts +61 -0
  5. package/apps/shared/components/admin/layout/AdminShell.tsx +73 -7
  6. package/apps/shared/components/admin/settings/BrandingForm.tsx +2 -1
  7. package/apps/shared/components/admin/settings/DomainDnsSetup.tsx +87 -24
  8. package/apps/shared/components/calendar/layout/CalendarShell.tsx +8 -2
  9. package/apps/shared/components/contacts/ContactsToolbar.tsx +125 -115
  10. package/apps/shared/components/contacts/layout/ContactsShell.tsx +15 -3
  11. package/apps/shared/components/layout/AppShell.tsx +411 -288
  12. package/apps/shared/components/layout/BrandingChrome.tsx +3 -2
  13. package/apps/shared/components/layout/KeyEnrollmentGate.tsx +398 -389
  14. package/apps/shared/components/layout/MailboxProvisioning.tsx +168 -126
  15. package/apps/shared/components/layout/UserMenu.tsx +303 -150
  16. package/apps/shared/components/mail/ConversationList.tsx +269 -253
  17. package/apps/shared/components/mail/ConversationThreadPane.tsx +475 -434
  18. package/apps/shared/components/mail/LazyReadingPane.tsx +115 -0
  19. package/apps/shared/components/mail/MailAddress.tsx +88 -0
  20. package/apps/shared/components/mail/MailSelectionBar.tsx +235 -222
  21. package/apps/shared/components/mail/MessageDetailPane.tsx +1458 -1383
  22. package/apps/shared/components/mail/NewMailToasts.tsx +141 -0
  23. package/apps/shared/components/mail/compose/ComposeContext.tsx +279 -160
  24. package/apps/shared/components/mail/compose/ComposeToolbar.tsx +422 -418
  25. package/apps/shared/components/mail/compose/ComposeWindow.tsx +1842 -1700
  26. package/apps/shared/components/mail/compose/ComposeWindowPlaceholder.tsx +111 -0
  27. package/apps/shared/components/mail/compose/RichTextEditor.tsx +147 -118
  28. package/apps/shared/components/mail/compose/SendFailureAlert.tsx +48 -0
  29. package/apps/shared/components/mail/compose/composePerf.ts +46 -0
  30. package/apps/shared/components/mail/compose/quotedBody.ts +161 -100
  31. package/apps/shared/components/mail/layout/MailShell.tsx +476 -445
  32. package/apps/shared/components/mail/unreadStyle.tsx +75 -0
  33. package/apps/shared/components/settings/layout/SettingsShell.tsx +252 -240
  34. package/apps/shared/components/tasks/layout/TasksShell.tsx +15 -3
  35. package/apps/shared/keyboard/GlobalShortcuts.tsx +51 -0
  36. package/apps/shared/keyboard/ShortcutProvider.tsx +62 -0
  37. package/apps/shared/keyboard/ShortcutsDialog.tsx +84 -0
  38. package/apps/shared/keyboard/dispatch.ts +124 -0
  39. package/apps/shared/keyboard/format.ts +89 -0
  40. package/apps/shared/keyboard/keymap.ts +114 -0
  41. package/apps/shared/keyboard/match.ts +44 -0
  42. package/apps/shared/keyboard/parse.ts +136 -0
  43. package/apps/shared/keyboard/platform.ts +34 -0
  44. package/apps/shared/keyboard/registry.ts +65 -0
  45. package/apps/shared/keyboard/targets.ts +79 -0
  46. package/apps/shared/keyboard/useShortcut.ts +50 -0
  47. package/apps/shared/keyboard/useShortcutProps.ts +17 -0
  48. package/apps/shared/mail/folderCounts.ts +302 -0
  49. package/apps/shared/mail/listSnapshots.ts +87 -0
  50. package/apps/shared/mail/mergeFirstPage.ts +47 -0
  51. package/apps/shared/mail/messageReadState.ts +85 -0
  52. package/apps/shared/mail/newMailNotifications.ts +183 -0
  53. package/apps/shared/mail/useMailConnection.ts +150 -0
  54. package/apps/shared/mail/useMailLiveUpdates.ts +232 -0
  55. package/apps/shared/mail/useMarkMessageRead.ts +47 -0
  56. package/apps/shared/mail/useNewMailNotifications.ts +163 -0
  57. package/apps/shared/mail/useUnreadTitle.ts +42 -0
  58. package/apps/shared/navigation/AppRouter.tsx +300 -0
  59. package/apps/shared/navigation/appHrefs.ts +23 -0
  60. package/apps/shared/navigation/frameContext.tsx +35 -0
  61. package/apps/shared/navigation/idle.ts +45 -0
  62. package/apps/shared/navigation/routerContext.tsx +83 -0
  63. package/apps/shared/navigation/routes.ts +72 -0
  64. package/apps/shared/search/LocalIndexLifecycle.tsx +114 -98
  65. package/apps/shared/styles/app.css +28 -10
  66. package/apps/www/_routedPage.tsx +24 -0
  67. package/apps/www/_routes.ts +35 -0
  68. package/apps/www/calendar/index.tsx +55 -19
  69. package/apps/www/contacts/[uid].tsx +112 -107
  70. package/apps/www/contacts/index.tsx +584 -567
  71. package/apps/www/index.tsx +2280 -1854
  72. package/apps/www/messages/[uid].tsx +106 -101
  73. package/apps/www/settings/auto-reply/index.tsx +4 -1
  74. package/apps/www/settings/encryption/index.tsx +1252 -1249
  75. package/apps/www/settings/filters/[uid].tsx +4 -1
  76. package/apps/www/settings/filters/index.tsx +102 -99
  77. package/apps/www/settings/filters/new/index.tsx +138 -133
  78. package/apps/www/settings/labels/index.tsx +204 -201
  79. package/apps/www/settings/privacy/index.tsx +4 -1
  80. package/apps/www/settings/read-receipts/index.tsx +4 -1
  81. package/apps/www/settings/sharing/index.tsx +277 -274
  82. package/apps/www/settings/signatures/[uid].tsx +170 -167
  83. package/apps/www/settings/signatures/index.tsx +88 -85
  84. package/apps/www/settings/signatures/new/index.tsx +134 -129
  85. package/apps/www/tasks/index.tsx +18 -2
  86. package/dist/apps/shared/auth/accountUrl.d.ts +2 -0
  87. package/dist/apps/shared/auth/accountUrl.js +8 -0
  88. package/dist/apps/shared/auth/adminAccess.d.ts +30 -0
  89. package/dist/apps/shared/auth/adminAccess.js +89 -0
  90. package/dist/apps/shared/components/admin/elevation.d.ts +24 -0
  91. package/dist/apps/shared/components/admin/elevation.js +56 -0
  92. package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +12 -4
  93. package/dist/apps/shared/components/admin/layout/AdminShell.js +49 -6
  94. package/dist/apps/shared/components/admin/settings/BrandingForm.js +1 -1
  95. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +31 -13
  96. package/dist/apps/shared/components/calendar/layout/CalendarShell.d.ts +1 -1
  97. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +8 -4
  98. package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +3 -1
  99. package/dist/apps/shared/components/contacts/ContactsToolbar.js +7 -4
  100. package/dist/apps/shared/components/contacts/layout/ContactsShell.d.ts +1 -1
  101. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +15 -5
  102. package/dist/apps/shared/components/layout/AppShell.d.ts +29 -4
  103. package/dist/apps/shared/components/layout/AppShell.js +73 -14
  104. package/dist/apps/shared/components/layout/BrandingChrome.d.ts +3 -2
  105. package/dist/apps/shared/components/layout/BrandingChrome.js +3 -2
  106. package/dist/apps/shared/components/layout/KeyEnrollmentGate.js +10 -9
  107. package/dist/apps/shared/components/layout/MailboxProvisioning.d.ts +5 -2
  108. package/dist/apps/shared/components/layout/MailboxProvisioning.js +45 -8
  109. package/dist/apps/shared/components/layout/UserMenu.d.ts +28 -9
  110. package/dist/apps/shared/components/layout/UserMenu.js +87 -14
  111. package/dist/apps/shared/components/mail/ConversationList.js +9 -13
  112. package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +4 -1
  113. package/dist/apps/shared/components/mail/ConversationThreadPane.js +53 -28
  114. package/dist/apps/shared/components/mail/LazyReadingPane.d.ts +9 -0
  115. package/dist/apps/shared/components/mail/LazyReadingPane.js +82 -0
  116. package/dist/apps/shared/components/mail/MailAddress.d.ts +27 -0
  117. package/dist/apps/shared/components/mail/MailAddress.js +39 -0
  118. package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +4 -1
  119. package/dist/apps/shared/components/mail/MailSelectionBar.js +11 -3
  120. package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +7 -1
  121. package/dist/apps/shared/components/mail/MessageDetailPane.js +87 -36
  122. package/dist/apps/shared/components/mail/NewMailToasts.d.ts +19 -0
  123. package/dist/apps/shared/components/mail/NewMailToasts.js +55 -0
  124. package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +30 -0
  125. package/dist/apps/shared/components/mail/compose/ComposeContext.js +71 -5
  126. package/dist/apps/shared/components/mail/compose/ComposeToolbar.js +4 -3
  127. package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +1 -1
  128. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +122 -27
  129. package/dist/apps/shared/components/mail/compose/ComposeWindowPlaceholder.d.ts +19 -0
  130. package/dist/apps/shared/components/mail/compose/ComposeWindowPlaceholder.js +33 -0
  131. package/dist/apps/shared/components/mail/compose/RichTextEditor.d.ts +9 -1
  132. package/dist/apps/shared/components/mail/compose/RichTextEditor.js +20 -2
  133. package/dist/apps/shared/components/mail/compose/SendFailureAlert.d.ts +14 -0
  134. package/dist/apps/shared/components/mail/compose/SendFailureAlert.js +11 -0
  135. package/dist/apps/shared/components/mail/compose/composePerf.d.ts +16 -0
  136. package/dist/apps/shared/components/mail/compose/composePerf.js +41 -0
  137. package/dist/apps/shared/components/mail/compose/quotedBody.d.ts +13 -0
  138. package/dist/apps/shared/components/mail/compose/quotedBody.js +67 -11
  139. package/dist/apps/shared/components/mail/layout/MailShell.d.ts +19 -4
  140. package/dist/apps/shared/components/mail/layout/MailShell.js +85 -85
  141. package/dist/apps/shared/components/mail/unreadStyle.d.ts +45 -0
  142. package/dist/apps/shared/components/mail/unreadStyle.js +61 -0
  143. package/dist/apps/shared/components/settings/layout/SettingsShell.d.ts +1 -1
  144. package/dist/apps/shared/components/settings/layout/SettingsShell.js +15 -5
  145. package/dist/apps/shared/components/tasks/layout/TasksShell.d.ts +1 -1
  146. package/dist/apps/shared/components/tasks/layout/TasksShell.js +15 -5
  147. package/dist/apps/shared/keyboard/GlobalShortcuts.d.ts +14 -0
  148. package/dist/apps/shared/keyboard/GlobalShortcuts.js +37 -0
  149. package/dist/apps/shared/keyboard/ShortcutProvider.d.ts +20 -0
  150. package/dist/apps/shared/keyboard/ShortcutProvider.js +52 -0
  151. package/dist/apps/shared/keyboard/ShortcutsDialog.d.ts +14 -0
  152. package/dist/apps/shared/keyboard/ShortcutsDialog.js +42 -0
  153. package/dist/apps/shared/keyboard/dispatch.d.ts +16 -0
  154. package/dist/apps/shared/keyboard/dispatch.js +109 -0
  155. package/dist/apps/shared/keyboard/format.d.ts +12 -0
  156. package/dist/apps/shared/keyboard/format.js +74 -0
  157. package/dist/apps/shared/keyboard/keymap.d.ts +294 -0
  158. package/dist/apps/shared/keyboard/keymap.js +84 -0
  159. package/dist/apps/shared/keyboard/match.d.ts +20 -0
  160. package/dist/apps/shared/keyboard/match.js +31 -0
  161. package/dist/apps/shared/keyboard/parse.d.ts +31 -0
  162. package/dist/apps/shared/keyboard/parse.js +107 -0
  163. package/dist/apps/shared/keyboard/platform.d.ts +15 -0
  164. package/dist/apps/shared/keyboard/platform.js +22 -0
  165. package/dist/apps/shared/keyboard/registry.d.ts +39 -0
  166. package/dist/apps/shared/keyboard/registry.js +33 -0
  167. package/dist/apps/shared/keyboard/targets.d.ts +14 -0
  168. package/dist/apps/shared/keyboard/targets.js +67 -0
  169. package/dist/apps/shared/keyboard/useShortcut.d.ts +19 -0
  170. package/dist/apps/shared/keyboard/useShortcut.js +35 -0
  171. package/dist/apps/shared/keyboard/useShortcutProps.d.ts +10 -0
  172. package/dist/apps/shared/keyboard/useShortcutProps.js +15 -0
  173. package/dist/apps/shared/mail/folderCounts.d.ts +78 -0
  174. package/dist/apps/shared/mail/folderCounts.js +212 -0
  175. package/dist/apps/shared/mail/listSnapshots.d.ts +46 -0
  176. package/dist/apps/shared/mail/listSnapshots.js +43 -0
  177. package/dist/apps/shared/mail/mergeFirstPage.d.ts +23 -0
  178. package/dist/apps/shared/mail/mergeFirstPage.js +30 -0
  179. package/dist/apps/shared/mail/messageReadState.d.ts +32 -0
  180. package/dist/apps/shared/mail/messageReadState.js +63 -0
  181. package/dist/apps/shared/mail/newMailNotifications.d.ts +62 -0
  182. package/dist/apps/shared/mail/newMailNotifications.js +138 -0
  183. package/dist/apps/shared/mail/useMailConnection.d.ts +55 -0
  184. package/dist/apps/shared/mail/useMailConnection.js +96 -0
  185. package/dist/apps/shared/mail/useMailLiveUpdates.d.ts +55 -0
  186. package/dist/apps/shared/mail/useMailLiveUpdates.js +182 -0
  187. package/dist/apps/shared/mail/useMarkMessageRead.d.ts +12 -0
  188. package/dist/apps/shared/mail/useMarkMessageRead.js +44 -0
  189. package/dist/apps/shared/mail/useNewMailNotifications.d.ts +41 -0
  190. package/dist/apps/shared/mail/useNewMailNotifications.js +110 -0
  191. package/dist/apps/shared/mail/useUnreadTitle.d.ts +18 -0
  192. package/dist/apps/shared/mail/useUnreadTitle.js +31 -0
  193. package/dist/apps/shared/navigation/AppRouter.d.ts +52 -0
  194. package/dist/apps/shared/navigation/AppRouter.js +242 -0
  195. package/dist/apps/shared/navigation/appHrefs.d.ts +14 -0
  196. package/dist/apps/shared/navigation/appHrefs.js +20 -0
  197. package/dist/apps/shared/navigation/frameContext.d.ts +19 -0
  198. package/dist/apps/shared/navigation/frameContext.js +24 -0
  199. package/dist/apps/shared/navigation/idle.d.ts +14 -0
  200. package/dist/apps/shared/navigation/idle.js +43 -0
  201. package/dist/apps/shared/navigation/routerContext.d.ts +37 -0
  202. package/dist/apps/shared/navigation/routerContext.js +56 -0
  203. package/dist/apps/shared/navigation/routes.d.ts +32 -0
  204. package/dist/apps/shared/navigation/routes.js +37 -0
  205. package/dist/apps/shared/search/LocalIndexLifecycle.js +17 -3
  206. package/dist/apps/shared/styles/app.css +28 -10
  207. package/dist/apps/www/_routedPage.d.ts +12 -0
  208. package/dist/apps/www/_routedPage.js +19 -0
  209. package/dist/apps/www/_routes.d.ts +11 -0
  210. package/dist/apps/www/_routes.js +29 -0
  211. package/dist/apps/www/calendar/index.d.ts +2 -2
  212. package/dist/apps/www/calendar/index.js +39 -8
  213. package/dist/apps/www/contacts/[uid].d.ts +3 -9
  214. package/dist/apps/www/contacts/[uid].js +6 -2
  215. package/dist/apps/www/contacts/index.d.ts +2 -2
  216. package/dist/apps/www/contacts/index.js +17 -4
  217. package/dist/apps/www/index.d.ts +2 -2
  218. package/dist/apps/www/index.js +361 -34
  219. package/dist/apps/www/messages/[uid].d.ts +3 -7
  220. package/dist/apps/www/messages/[uid].js +7 -4
  221. package/dist/apps/www/settings/auto-reply/index.d.ts +2 -2
  222. package/dist/apps/www/settings/auto-reply/index.js +3 -1
  223. package/dist/apps/www/settings/encryption/index.d.ts +2 -2
  224. package/dist/apps/www/settings/encryption/index.js +3 -1
  225. package/dist/apps/www/settings/filters/[uid].d.ts +2 -2
  226. package/dist/apps/www/settings/filters/[uid].js +3 -1
  227. package/dist/apps/www/settings/filters/index.d.ts +2 -2
  228. package/dist/apps/www/settings/filters/index.js +3 -1
  229. package/dist/apps/www/settings/filters/new/index.d.ts +2 -2
  230. package/dist/apps/www/settings/filters/new/index.js +6 -2
  231. package/dist/apps/www/settings/labels/index.d.ts +2 -2
  232. package/dist/apps/www/settings/labels/index.js +3 -1
  233. package/dist/apps/www/settings/privacy/index.d.ts +2 -2
  234. package/dist/apps/www/settings/privacy/index.js +3 -1
  235. package/dist/apps/www/settings/read-receipts/index.d.ts +2 -2
  236. package/dist/apps/www/settings/read-receipts/index.js +3 -1
  237. package/dist/apps/www/settings/sharing/index.d.ts +2 -2
  238. package/dist/apps/www/settings/sharing/index.js +3 -1
  239. package/dist/apps/www/settings/signatures/[uid].d.ts +2 -2
  240. package/dist/apps/www/settings/signatures/[uid].js +3 -1
  241. package/dist/apps/www/settings/signatures/index.d.ts +2 -2
  242. package/dist/apps/www/settings/signatures/index.js +3 -1
  243. package/dist/apps/www/settings/signatures/new/index.d.ts +2 -2
  244. package/dist/apps/www/settings/signatures/new/index.js +6 -2
  245. package/dist/apps/www/tasks/index.d.ts +2 -2
  246. package/dist/apps/www/tasks/index.js +15 -3
  247. package/package.json +2 -2
@@ -1,11 +1,7 @@
1
- import React from "react";
2
1
  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 & {
2
+ declare const _default: import("../../shared/navigation/AppRouter.js").RoutedPageComponent<MailShellProps & {
8
3
  params: {
9
4
  uid: string;
10
5
  };
11
- }): React.JSX.Element;
6
+ }>;
7
+ export default _default;
@@ -3,19 +3,21 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../_routedPage.js";
6
7
  import { useEffect, useState } from "react";
7
8
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
9
  import { getMessage } from "@rapidmx/react-shared/mail/mailApi.js";
9
10
  import { listLabels } from "@rapidmx/react-shared/mail/labelsApi.js";
10
- import { useMarkMessageRead, useMessageAttachments } from "@rapidmx/react-shared/mail/mailDetailHooks.js";
11
+ import { useMessageAttachments } from "@rapidmx/react-shared/mail/mailDetailHooks.js";
12
+ import { useMarkMessageRead } from "../../shared/mail/useMarkMessageRead.js";
11
13
  import MailShell, { useMailShell } from "../../shared/components/mail/layout/MailShell.js";
12
- import MessageDetailPane from "../../shared/components/mail/MessageDetailPane.js";
14
+ import { LazyMessageDetailPane } from "../../shared/components/mail/LazyReadingPane.js";
13
15
  import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
14
16
  /**
15
17
  * Only reached on mobile (below the `md` breakpoint) — desktop's `apps/www/index.tsx` keeps its existing
16
18
  * inline reading pane and never navigates here; see that file's `handleSelect`.
17
19
  */
18
- export default function MessageDetailPage(props) {
20
+ function MessageDetailPage(props) {
19
21
  return (_jsx(MailShell, { ...props, children: _jsx(MessageDetailContent, { uid: props.params.uid }) }));
20
22
  }
21
23
  function MessageDetailContent({ uid }) {
@@ -68,5 +70,6 @@ function MessageDetailContent({ uid }) {
68
70
  const isSentItems = folders.find((f) => f.uid === message.folderUid)?.type === "sent_items";
69
71
  const isOutbox = folders.find((f) => f.uid === message.folderUid)?.type === "outbox";
70
72
  const draftsFolderUid = folders.find((f) => f.type === "drafts")?.uid;
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
+ return (_jsx(LazyMessageDetailPane, { shortcuts: true, 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]) }));
72
74
  }
75
+ export default routedPage("/messages/:uid", MessageDetailPage);
@@ -1,4 +1,4 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
2
  export type SettingsAutoReplyPageProps = Omit<SettingsShellProps, "active">;
4
- export default function SettingsAutoReplyPage(props: SettingsAutoReplyPageProps): React.JSX.Element;
3
+ declare const _default: import("../../../shared/navigation/AppRouter.js").RoutedPageComponent<SettingsAutoReplyPageProps>;
4
+ export default _default;
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../_routedPage.js";
6
7
  import { useState } from "react";
7
8
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
9
  import { toDatetimeLocal } from "@rapidmx/react-shared/util/dateInput.js";
@@ -11,7 +12,7 @@ import SettingsShell, { useSettingsShell } from "../../../shared/components/sett
11
12
  import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
12
13
  import Button from "@rapidmx/react-shared/components/buttons/Button.js";
13
14
  const INPUT_CLASS = "w-full text-sm py-2 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
14
- export default function SettingsAutoReplyPage(props) {
15
+ function SettingsAutoReplyPage(props) {
15
16
  return (_jsx(SettingsShell, { ...props, active: "auto-reply", children: _jsx(AutoReplyContent, {}) }));
16
17
  }
17
18
  function AutoReplyContent() {
@@ -57,3 +58,4 @@ function AutoReplyContent() {
57
58
  }
58
59
  return (_jsx("div", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: _jsxs("div", { className: "max-w-xl", children: [_jsx("h1", { className: "text-lg font-bold tracking-tight mb-1", children: "Automatic Replies" }), _jsxs("p", { className: "text-sm text-text-muted mb-4", children: ["Send an automatic reply to anyone who emails ", mailbox.displayName, " while you\u2019re away. A calendar event with its own automatic reply enabled takes over for its own start/end window."] }), error && _jsx(Alert, { children: error }), saved && !error && _jsx("div", { className: "mb-4 text-sm text-success font-medium", children: "Saved." }), _jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs("label", { className: "flex items-center gap-2 text-sm font-medium", children: [_jsx("input", { type: "checkbox", checked: oofEnabled, onChange: (e) => setOofEnabled(e.target.checked) }), "Automatic replies are on"] }), oofEnabled && (_jsxs(_Fragment, { children: [_jsxs("label", { className: "flex flex-col gap-1.5 text-sm", children: [_jsx("span", { className: "font-semibold", children: "Message" }), _jsx("textarea", { "aria-label": "Automatic reply message", className: INPUT_CLASS, rows: 5, value: oofMessage, onChange: (e) => setOofMessage(e.target.value) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("label", { className: "flex flex-col gap-1.5 text-sm", children: [_jsx("span", { className: "font-semibold", children: "Start (optional)" }), _jsx("input", { type: "datetime-local", "aria-label": "Automatic reply start", className: INPUT_CLASS, value: oofStartTime, onChange: (e) => setOofStartTime(e.target.value) })] }), _jsxs("label", { className: "flex flex-col gap-1.5 text-sm", children: [_jsx("span", { className: "font-semibold", children: "End (optional)" }), _jsx("input", { type: "datetime-local", "aria-label": "Automatic reply end", className: INPUT_CLASS, value: oofEndTime, onChange: (e) => setOofEndTime(e.target.value) })] })] }), _jsx("p", { className: "text-xs text-text-muted -mt-2", children: "Leave both blank to stay on indefinitely until turned off." })] })), _jsx("div", { children: _jsx(Button, { type: "submit", loading: saving, disabled: saving, className: "!w-auto", children: "Save" }) })] })] }) }));
59
60
  }
61
+ export default routedPage("/settings/auto-reply", SettingsAutoReplyPage);
@@ -1,7 +1,7 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
2
  /** Mirrors restapi's `BaseKeyVaultRoute` `MAX_MASTER_KEY_WRAPS` - `addMasterKeyWrap()` refuses a vault
4
3
  * already holding this many wraps (escrow included). */
5
4
  export declare const MAX_MASTER_KEY_WRAPS = 20;
6
5
  export type SettingsEncryptionPageProps = Omit<SettingsShellProps, "active">;
7
- export default function SettingsEncryptionPage(props: SettingsEncryptionPageProps): React.JSX.Element;
6
+ declare const _default: import("../../../shared/navigation/AppRouter.js").RoutedPageComponent<SettingsEncryptionPageProps>;
7
+ export default _default;
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../_routedPage.js";
6
7
  import { useEffect, useState } from "react";
7
8
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
9
  import { addMasterKeyWrap, cancelSignEnrollment, checkSignEnrollmentStatus, findActivePublicKey, getEscrowInfo, getKeyVault, rekey, removeMasterKeyWrap, startSignEnrollment, } from "@rapidmx/react-shared/crypto/keyvaultApi.js";
@@ -170,7 +171,7 @@ function idleTimeoutLabel(minutes) {
170
171
  }
171
172
  return `${minutes} minutes`;
172
173
  }
173
- export default function SettingsEncryptionPage(props) {
174
+ function SettingsEncryptionPage(props) {
174
175
  return (_jsx(SettingsShell, { ...props, active: "encryption", children: _jsx(EncryptionGate, { userUid: props.userUid, impersonating: props.impersonating }) }));
175
176
  }
176
177
  /**
@@ -773,3 +774,4 @@ function EncryptionContent({ canManageKeys }) {
773
774
  ? "Checking whether a signing certificate enrollment is still in progress..."
774
775
  : "Rotation is unavailable while a signing certificate enrollment is in progress - rotating now would lose the key being enrolled. Try again once it finishes, or cancel the enrollment." })), signingStatus === "pending" && signingEnrollmentId && (_jsxs("div", { className: "flex flex-col gap-2", children: [cancelEnrollmentError && _jsx(Alert, { children: cancelEnrollmentError }), _jsx("div", { children: _jsx(Button, { type: "button", variant: "secondary", className: "!w-auto", loading: cancelingEnrollment, disabled: cancelingEnrollment, onClick: () => handleCancelEnrollment(signingEnrollmentId), children: "Cancel enrollment" }) })] })), _jsx("input", { type: "password", "aria-label": "New password for rotated keys", placeholder: "New password", className: "w-full text-sm border border-border rounded-sm py-1.5 px-2 bg-surface", value: rotationPassword, onChange: (e) => setRotationPassword(e.target.value), disabled: rotating || rotationBlockedBySigning, autoComplete: "new-password" }), _jsx("input", { type: "password", "aria-label": "Confirm new password for rotated keys", placeholder: "Confirm new password", className: "w-full text-sm border border-border rounded-sm py-1.5 px-2 bg-surface", value: rotationConfirmPassword, onChange: (e) => setRotationConfirmPassword(e.target.value), disabled: rotating || rotationBlockedBySigning, autoComplete: "new-password" }), _jsx("div", { children: _jsx(Button, { type: "submit", variant: "secondary", className: "!w-auto text-danger", loading: rotating, disabled: rotating || rotationBlockedBySigning, children: "Rotate keys now" }) })] })] })), _jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold mb-2", children: "Session timeout" }), _jsx("p", { className: "text-xs text-text-muted mb-3", children: "Automatically destroys your unlocked keys on this device after this much time with no activity anywhere in the app - not just Mail or Settings. Applies the next time you open or reload the app." }), _jsx("select", { "aria-label": "Session timeout", className: "text-sm border border-border rounded-sm py-1.5 px-2 bg-surface", value: idleTimeoutMinutes, onChange: handleIdleTimeoutChange, children: IDLE_TIMEOUT_OPTIONS_MINUTES.map((minutes) => (_jsx("option", { value: minutes, children: idleTimeoutLabel(minutes) }, minutes))) })] }), _jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold mb-2", children: "Local search index size" }), _jsxs("p", { className: "text-xs text-text-muted mb-3", children: ["How much decrypted mail this device keeps in a local encrypted search index, so recent search results and inbox previews work instantly without contacting the server every time. Defaults to ", localIndexDefaultByteBudgetLabel, " on this device. Applies the next time this mailbox\u2019s index rebuilds (e.g. the next time you unlock it) \u2014 lowering it doesn\u2019t delete anything already indexed elsewhere, it just narrows what this device keeps a local copy of."] }), _jsx("select", { "aria-label": "Local search index size", className: "text-sm border border-border rounded-sm py-1.5 px-2 bg-surface", value: localIndexByteBudget, onChange: handleLocalIndexByteBudgetChange, children: LOCAL_INDEX_SIZE_OPTIONS.map((option) => (_jsx("option", { value: option.bytes, children: option.label }, option.bytes))) })] }), _jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold mb-2", children: "This session" }), _jsx("p", { className: "text-xs text-text-muted mb-3", children: "Removes your unlocked keys from this browser tab\u2019s memory right now, without affecting any other device. You\u2019ll be asked to unlock again the next time you read or send encrypted mail here." }), _jsx(Button, { type: "button", variant: "secondary", className: "!w-auto text-danger", onClick: handleDestroyKeysNow, children: "Destroy keys on this device now" })] })] }) }));
775
776
  }
777
+ export default routedPage("/settings/encryption", SettingsEncryptionPage);
@@ -1,8 +1,8 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
2
  export type MailFilterDetailPageProps = Omit<SettingsShellProps, "active"> & {
4
3
  params: {
5
4
  uid: string;
6
5
  };
7
6
  };
8
- export default function MailFilterDetailPage(props: MailFilterDetailPageProps): React.JSX.Element;
7
+ declare const _default: import("../../../shared/navigation/AppRouter.js").RoutedPageComponent<MailFilterDetailPageProps>;
8
+ export default _default;
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../_routedPage.js";
6
7
  import { useEffect, useState } from "react";
7
8
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
9
  import { listFolders } from "@rapidmx/react-shared/mail/mailApi.js";
@@ -14,7 +15,7 @@ import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
14
15
  import Button from "@rapidmx/react-shared/components/buttons/Button.js";
15
16
  import FormField from "@rapidmx/react-shared/components/forms/FormField.js";
16
17
  const INPUT_CLASS = "w-full text-sm py-2.5 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
17
- export default function MailFilterDetailPage(props) {
18
+ function MailFilterDetailPage(props) {
18
19
  return (_jsx(SettingsShell, { ...props, active: "filters", children: _jsx(MailFilterDetailContent, { uid: props.params.uid }) }));
19
20
  }
20
21
  function MailFilterDetailContent({ uid }) {
@@ -107,3 +108,4 @@ function MailFilterDetailContent({ uid }) {
107
108
  }
108
109
  return (_jsx("div", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: _jsxs("div", { className: "max-w-3xl", children: [_jsx("a", { href: `/settings/filters?mailboxUid=${encodeURIComponent(mailboxUid)}`, className: "text-sm text-primary-dark hover:underline", children: "\u2190 All mail filters" }), _jsx("h1", { className: "text-lg font-bold tracking-tight mt-1 mb-5", children: original.name }), error && _jsx(Alert, { children: error }), saved && !error && _jsx("div", { className: "mb-4 text-sm text-success font-medium", children: "Saved." }), _jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-5", children: [_jsx("div", { className: "bg-surface border border-border rounded-md p-6", children: _jsx(FormField, { label: "Name", htmlFor: "name", children: _jsx("input", { id: "name", type: "text", className: INPUT_CLASS, value: name, onChange: (e) => setName(e.target.value) }) }) }), _jsx(RuleBuilder, { value: rule, onChange: setRule, conditionFields: MAIL_FILTER_CONDITION_FIELDS, actionTypes: buildMailFilterActionTypes(folders), showValidation: showValidation }), _jsx("div", { children: _jsx(Button, { type: "submit", loading: saving, disabled: saving, className: "!w-auto", children: "Save changes" }) })] })] }) }));
109
110
  }
111
+ export default routedPage("/settings/filters/:uid", MailFilterDetailPage);
@@ -1,4 +1,4 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
2
  export type SettingsFiltersPageProps = Omit<SettingsShellProps, "active">;
4
- export default function SettingsFiltersPage(props: SettingsFiltersPageProps): React.JSX.Element;
3
+ declare const _default: import("../../../shared/navigation/AppRouter.js").RoutedPageComponent<SettingsFiltersPageProps>;
4
+ export default _default;
@@ -3,13 +3,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../_routedPage.js";
6
7
  import { useEffect, useState } from "react";
7
8
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
9
  import { listMailFilterRules } from "@rapidmx/react-shared/mail/mailFilterRulesApi.js";
9
10
  import SettingsShell, { useSettingsShell } from "../../../shared/components/settings/layout/SettingsShell.js";
10
11
  import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
11
12
  import Button from "@rapidmx/react-shared/components/buttons/Button.js";
12
- export default function SettingsFiltersPage(props) {
13
+ function SettingsFiltersPage(props) {
13
14
  return (_jsx(SettingsShell, { ...props, active: "filters", children: _jsx(FiltersContent, {}) }));
14
15
  }
15
16
  function FiltersContent() {
@@ -28,3 +29,4 @@ function FiltersContent() {
28
29
  const sorted = [...rules].sort((a, b) => a.sequence - b.sequence);
29
30
  return (_jsx("div", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: _jsxs("div", { className: "max-w-3xl", children: [_jsxs("div", { className: "flex items-center justify-between mb-5", children: [_jsx("h1", { className: "text-lg font-bold tracking-tight", children: "Mail Filters" }), _jsx("a", { href: `/settings/filters/new?mailboxUid=${encodeURIComponent(mailboxUid)}`, children: _jsx(Button, { type: "button", className: "!w-auto", children: "+ New filter" }) })] }), _jsx("p", { className: "text-sm text-text-muted mb-4", children: "Applied in order once a message is verdicted safe to deliver, before it reaches your Inbox." }), error && _jsx(Alert, { children: error }), loading ? (_jsx("p", { className: "text-sm text-text-muted", children: "Loading\u2026" })) : sorted.length === 0 ? (_jsx("p", { className: "text-sm text-text-muted", children: "No mail filters yet." })) : (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm border-collapse", children: [_jsx("thead", { children: _jsx("tr", { children: ["Sequence", "Name", "Enabled", "Actions", ""].map((h) => (_jsx("th", { className: "text-left text-xs uppercase tracking-wide text-text-muted py-2 px-2.5 border-b border-border", children: h }, h))) }) }), _jsx("tbody", { children: sorted.map((rule) => (_jsxs("tr", { children: [_jsx("td", { className: "py-2.5 px-2.5 border-b border-border", children: rule.sequence }), _jsx("td", { className: "py-2.5 px-2.5 border-b border-border", children: rule.name }), _jsx("td", { className: "py-2.5 px-2.5 border-b border-border", children: rule.enabled ? "Yes" : "No" }), _jsx("td", { className: "py-2.5 px-2.5 border-b border-border", children: rule.actions.length }), _jsx("td", { className: "py-2.5 px-2.5 border-b border-border text-right", children: _jsx("a", { href: `/settings/filters/${encodeURIComponent(rule.uid)}?mailboxUid=${encodeURIComponent(mailboxUid)}`, className: "text-primary-dark hover:underline font-medium", children: "View" }) })] }, rule.uid))) })] }) }))] }) }));
30
31
  }
32
+ export default routedPage("/settings/filters", SettingsFiltersPage);
@@ -1,4 +1,4 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../../shared/components/settings/layout/SettingsShell.js";
3
2
  export type NewMailFilterPageProps = Omit<SettingsShellProps, "active">;
4
- export default function NewMailFilterPage(props: NewMailFilterPageProps): React.JSX.Element;
3
+ declare const _default: import("../../../../shared/navigation/AppRouter.js").RoutedPageComponent<NewMailFilterPageProps>;
4
+ export default _default;
@@ -3,6 +3,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../../_routedPage.js";
7
+ import { useNavigate } from "../../../../shared/navigation/AppRouter.js";
6
8
  import { useEffect, useState } from "react";
7
9
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
10
  import { listFolders } from "@rapidmx/react-shared/mail/mailApi.js";
@@ -14,10 +16,11 @@ import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
14
16
  import Button from "@rapidmx/react-shared/components/buttons/Button.js";
15
17
  import FormField from "@rapidmx/react-shared/components/forms/FormField.js";
16
18
  const INPUT_CLASS = "w-full text-sm py-2.5 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
17
- export default function NewMailFilterPage(props) {
19
+ function NewMailFilterPage(props) {
18
20
  return (_jsx(SettingsShell, { ...props, active: "filters", children: _jsx(NewMailFilterForm, {}) }));
19
21
  }
20
22
  function NewMailFilterForm() {
23
+ const navigate = useNavigate();
21
24
  const { mailboxUid } = useSettingsShell();
22
25
  const [folders, setFolders] = useState(null);
23
26
  const [folderError, setFolderError] = useState(null);
@@ -54,7 +57,7 @@ function NewMailFilterForm() {
54
57
  setSaving(true);
55
58
  try {
56
59
  const created = await createMailFilterRule({ mailboxUid: mailboxUid, name: name.trim(), ...rule });
57
- window.location.href = `/settings/filters/${encodeURIComponent(created.uid)}?mailboxUid=${encodeURIComponent(mailboxUid)}`;
60
+ navigate(`/settings/filters/${encodeURIComponent(created.uid)}?mailboxUid=${encodeURIComponent(mailboxUid)}`);
58
61
  }
59
62
  catch (err) {
60
63
  setError(err instanceof ApiRequestError ? err.message : "Could not create the mail filter.");
@@ -65,3 +68,4 @@ function NewMailFilterForm() {
65
68
  }
66
69
  return (_jsx("div", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: _jsxs("div", { className: "max-w-3xl", children: [_jsx("h1", { className: "text-lg font-bold tracking-tight mb-1", children: "New mail filter" }), _jsx("p", { className: "text-sm text-text-muted mb-5", children: "Applied in order once a message is verdicted safe to deliver, before it reaches your Inbox." }), error && _jsx(Alert, { children: error }), folderError && _jsx(Alert, { children: folderError }), folders === null ? (_jsx("p", { className: "text-sm text-text-muted", children: "Loading\u2026" })) : (_jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-5", children: [_jsx("div", { className: "bg-surface border border-border rounded-md p-6", children: _jsx(FormField, { label: "Name", htmlFor: "name", children: _jsx("input", { id: "name", type: "text", className: INPUT_CLASS, value: name, onChange: (e) => setName(e.target.value), placeholder: "File newsletters" }) }) }), _jsx(RuleBuilder, { value: rule, onChange: setRule, conditionFields: MAIL_FILTER_CONDITION_FIELDS, actionTypes: buildMailFilterActionTypes(folders), showValidation: showValidation }), _jsxs("div", { className: "flex gap-3", children: [_jsx(Button, { type: "submit", loading: saving, disabled: saving, className: "!w-auto", children: "Create filter" }), _jsx("a", { href: `/settings/filters?mailboxUid=${encodeURIComponent(mailboxUid)}`, children: _jsx(Button, { type: "button", variant: "secondary", className: "!w-auto", children: "Cancel" }) })] })] }))] }) }));
67
70
  }
71
+ export default routedPage("/settings/filters/new", NewMailFilterPage);
@@ -1,4 +1,4 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
2
  export type SettingsLabelsPageProps = Omit<SettingsShellProps, "active">;
4
- export default function SettingsLabelsPage(props: SettingsLabelsPageProps): React.JSX.Element;
3
+ declare const _default: import("../../../shared/navigation/AppRouter.js").RoutedPageComponent<SettingsLabelsPageProps>;
4
+ export default _default;
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../_routedPage.js";
6
7
  import { useEffect, useState } from "react";
7
8
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
9
  import { createLabel, deleteLabel, listLabels, updateLabel } from "@rapidmx/react-shared/mail/labelsApi.js";
@@ -11,7 +12,7 @@ import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
11
12
  import Button from "@rapidmx/react-shared/components/buttons/Button.js";
12
13
  import FormField from "@rapidmx/react-shared/components/forms/FormField.js";
13
14
  import Modal from "@rapidmx/react-shared/components/overlays/Modal.js";
14
- export default function SettingsLabelsPage(props) {
15
+ function SettingsLabelsPage(props) {
15
16
  return (_jsx(SettingsShell, { ...props, active: "labels", children: _jsx(LabelsContent, {}) }));
16
17
  }
17
18
  const DEFAULT_COLOR = "#6366f1";
@@ -93,3 +94,4 @@ function LabelsContent() {
93
94
  setDeleteError(null);
94
95
  }, children: "Delete" })] })] }, label.uid))) }))] }), _jsxs(Modal, { open: formOpen, onClose: () => setFormOpen(false), title: editing ? "Edit label" : "New label", children: [formError && _jsx(Alert, { children: formError }), _jsx(FormField, { label: "Name", htmlFor: "label-name", children: _jsx("input", { id: "label-name", type: "text", value: formName, onChange: (e) => setFormName(e.target.value), className: "w-full text-sm px-3 py-1.5 rounded-md border border-border bg-surface" }) }), _jsx(FormField, { label: "Color", htmlFor: "label-color", children: _jsx("input", { id: "label-color", type: "color", value: formColor, onChange: (e) => setFormColor(e.target.value), className: "h-9 w-16 rounded-md border border-border bg-surface" }) }), _jsxs("div", { className: "flex justify-end gap-2 mt-2", children: [_jsx(Button, { type: "button", variant: "secondary", className: "!w-auto", onClick: () => setFormOpen(false), children: "Cancel" }), _jsx(Button, { type: "button", className: "!w-auto", loading: saving, disabled: saving || !formName.trim(), onClick: handleSave, children: "Save" })] })] }), _jsxs(Modal, { open: !!deleting, onClose: () => setDeleting(null), title: "Delete this label?", children: [deleteError && _jsx(Alert, { children: deleteError }), _jsxs("p", { className: "text-sm text-text-muted mb-4", children: ["This removes \u201C", deleting?.name, "\u201D from every message it's applied to. This can't be undone."] }), _jsxs("div", { className: "flex justify-end gap-2", children: [_jsx(Button, { type: "button", variant: "secondary", className: "!w-auto", onClick: () => setDeleting(null), children: "Cancel" }), _jsx(Button, { type: "button", className: "!w-auto", loading: deleteBusy, disabled: deleteBusy, onClick: handleDelete, children: "Delete label" })] })] })] }));
95
96
  }
97
+ export default routedPage("/settings/labels", SettingsLabelsPage);
@@ -1,4 +1,4 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
2
  export type SettingsPrivacyPageProps = Omit<SettingsShellProps, "active">;
4
- export default function SettingsPrivacyPage(props: SettingsPrivacyPageProps): React.JSX.Element;
3
+ declare const _default: import("../../../shared/navigation/AppRouter.js").RoutedPageComponent<SettingsPrivacyPageProps>;
4
+ export default _default;
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../_routedPage.js";
6
7
  import { useEffect, useRef, useState } from "react";
7
8
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
9
  import { createExportRequest, exportRequestDownloadUrl, listExportRequests, } from "@rapidmx/react-shared/mail/dataExportApi.js";
@@ -31,7 +32,7 @@ function statusBadgeClass(status) {
31
32
  function statusLabel(status) {
32
33
  return status.replace(/_/g, " ");
33
34
  }
34
- export default function SettingsPrivacyPage(props) {
35
+ function SettingsPrivacyPage(props) {
35
36
  return (_jsx(SettingsShell, { ...props, active: "privacy", children: _jsx(PrivacyContent, { userUid: props.userUid }) }));
36
37
  }
37
38
  function PrivacyContent({ userUid }) {
@@ -200,3 +201,4 @@ function ErasureSection({ mailboxLabel }) {
200
201
  }
201
202
  return (_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold mb-2", children: "Delete my account" }), _jsxs("p", { className: "text-xs text-text-muted mb-3", children: ["Permanently and irreversibly deletes ", _jsx("strong", { children: mailboxLabel }), " and everything in it, once a compliance administrator reviews and approves the request. There is no way to cancel a request or undo the deletion once it runs."] }), loadError && _jsx(Alert, { children: loadError }), loading ? (_jsx("p", { className: "text-sm text-text-muted", children: "Loading\u2026" })) : (_jsxs(_Fragment, { children: [requests.length > 0 && (_jsx("ul", { className: "flex flex-col gap-2 mb-3", children: requests.map((request) => (_jsxs("li", { className: "flex items-center justify-between gap-3 text-sm py-1.5 px-3 bg-surface-alt rounded-sm", children: [_jsxs("span", { children: [new Date(request.dateCreated).toLocaleString(), request.status === "denied" && request.reason && (_jsxs("span", { className: "text-danger", children: [" \u2014 ", request.reason] }))] }), _jsx("span", { className: `text-xs font-bold uppercase tracking-wide py-0.5 px-2 rounded-pill ${statusBadgeClass(request.status)}`, children: statusLabel(request.status) })] }, request.uid))) })), _jsx(Button, { type: "button", variant: "secondary", className: "!w-auto !border-danger !text-danger hover:!border-danger hover:!text-danger", disabled: hasPending, onClick: () => setConfirming(true), children: "Request account erasure" })] })), _jsxs(Modal, { open: confirming, onClose: closeConfirm, title: "Delete my account", children: [_jsxs("p", { className: "text-sm mb-5", children: ["This permanently deletes ", mailboxLabel, " and everything in it \u2014 messages, contacts, calendar, tasks, and notes \u2014 once approved. This cannot be undone and cannot be cancelled once submitted."] }), createError && _jsx(Alert, { children: createError }), _jsxs("div", { className: "flex gap-3 justify-end mt-5", children: [_jsx(Button, { type: "button", variant: "secondary", className: "!w-auto", disabled: creating, onClick: closeConfirm, children: "Cancel" }), _jsx(Button, { type: "button", className: "!w-auto !bg-none !bg-danger !border-danger hover:!bg-danger", loading: creating, disabled: creating, onClick: handleConfirm, children: "Request erasure" })] })] })] }));
202
203
  }
204
+ export default routedPage("/settings/privacy", SettingsPrivacyPage);
@@ -1,4 +1,4 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
2
  export type SettingsReadReceiptsPageProps = Omit<SettingsShellProps, "active">;
4
- export default function SettingsReadReceiptsPage(props: SettingsReadReceiptsPageProps): React.JSX.Element;
3
+ declare const _default: import("../../../shared/navigation/AppRouter.js").RoutedPageComponent<SettingsReadReceiptsPageProps>;
4
+ export default _default;
@@ -3,13 +3,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../_routedPage.js";
6
7
  import { useState } from "react";
7
8
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
9
  import { updateMailbox } from "@rapidmx/react-shared/mail/mailApi.js";
9
10
  import SettingsShell, { useSettingsShell } from "../../../shared/components/settings/layout/SettingsShell.js";
10
11
  import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
11
12
  import Button from "@rapidmx/react-shared/components/buttons/Button.js";
12
- export default function SettingsReadReceiptsPage(props) {
13
+ function SettingsReadReceiptsPage(props) {
13
14
  return (_jsx(SettingsShell, { ...props, active: "read-receipts", children: _jsx(ReadReceiptsContent, {}) }));
14
15
  }
15
16
  function ReadReceiptsContent() {
@@ -56,3 +57,4 @@ function ReadReceiptsContent() {
56
57
  }
57
58
  return (_jsx("div", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: _jsxs("div", { className: "max-w-xl", children: [_jsx("h1", { className: "text-lg font-bold tracking-tight mb-1", children: "Read Receipts" }), _jsx("p", { className: "text-sm text-text-muted mb-4", children: "Controls when this mailbox requests a delivery/read receipt on mail it sends, and how it responds to a receipt requested of it. A per-message \u201CRequest a read receipt\u201D checkbox in Compose always overrides the request-side settings below for that one message." }), error && _jsx(Alert, { children: error }), saved && !error && _jsx("div", { className: "mb-4 text-sm text-success font-medium", children: "Saved." }), _jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-5", children: [_jsxs("fieldset", { className: "flex flex-col gap-2", children: [_jsx("legend", { className: "text-sm font-semibold mb-1", children: "Request receipts when sending" }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: alwaysRequestReceiptInternal, onChange: (e) => setAlwaysRequestReceiptInternal(e.target.checked) }), "From internal recipients (mail to this organization)"] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: alwaysRequestReceiptFederated, onChange: (e) => setAlwaysRequestReceiptFederated(e.target.checked) }), "From federated recipients (partner organizations)"] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: alwaysRequestReceiptExternal, onChange: (e) => setAlwaysRequestReceiptExternal(e.target.checked) }), "From external recipients"] })] }), _jsxs("fieldset", { className: "flex flex-col gap-2", children: [_jsx("legend", { className: "text-sm font-semibold mb-1", children: "Respond automatically to requests" }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: autoSendReceiptsInternal, onChange: (e) => setAutoSendReceiptsInternal(e.target.checked) }), "From internal senders"] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: autoSendReceiptsFederated, onChange: (e) => setAutoSendReceiptsFederated(e.target.checked) }), "From federated senders (partner organizations)"] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: autoSendReceiptsExternal, onChange: (e) => setAutoSendReceiptsExternal(e.target.checked) }), "From external senders"] }), _jsx("p", { className: "text-xs text-text-muted", children: "Unchecked means a request from that sender waits in your Inbox for you to send or decline it explicitly." })] }), _jsx("div", { children: _jsx(Button, { type: "submit", loading: saving, disabled: saving, className: "!w-auto", children: "Save" }) })] })] }) }));
58
59
  }
60
+ export default routedPage("/settings/read-receipts", SettingsReadReceiptsPage);
@@ -1,4 +1,4 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
2
  export type SettingsSharingPageProps = Omit<SettingsShellProps, "active">;
4
- export default function SettingsSharingPage(props: SettingsSharingPageProps): React.JSX.Element;
3
+ declare const _default: import("../../../shared/navigation/AppRouter.js").RoutedPageComponent<SettingsSharingPageProps>;
4
+ export default _default;
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../_routedPage.js";
6
7
  import { useEffect, useState } from "react";
7
8
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
9
  import { listMailboxAccess, lookupMailboxOwnerByEmail, removeMailboxAccess, setMailboxAccess, } from "@rapidmx/react-shared/mail/mailboxAccessApi.js";
@@ -12,7 +13,7 @@ import Button from "@rapidmx/react-shared/components/buttons/Button.js";
12
13
  import Modal from "@rapidmx/react-shared/components/overlays/Modal.js";
13
14
  import { SkeletonList } from "@rapidmx/react-shared/components/feedback/Skeleton.js";
14
15
  const ROLE_LABELS = { viewer: "Can view", manager: "Can manage" };
15
- export default function SettingsSharingPage(props) {
16
+ function SettingsSharingPage(props) {
16
17
  return (_jsx(SettingsShell, { ...props, active: "sharing", children: _jsx(SharingContent, {}) }));
17
18
  }
18
19
  /**
@@ -122,3 +123,4 @@ function SharingContent() {
122
123
  }
123
124
  return (_jsx("div", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: _jsxs("div", { className: "max-w-xl flex flex-col gap-6", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-lg font-bold tracking-tight mb-1", children: "Sharing" }), _jsxs("p", { className: "text-sm text-text-muted", children: ["Manage who else can access ", mailbox?.displayName ?? "this mailbox", "\u2019s mail, calendar, contacts, and tasks. Granting access here covers all of it at once - there\u2019s nothing else to configure per data type."] })] }), status === "loading" && _jsx(SkeletonList, { count: 3 }), status === "forbidden" && (_jsx(Alert, { children: "You don\u2019t have permission to manage sharing for this mailbox." })), status === "error" && error && _jsx(Alert, { children: error }), status === "ready" && (_jsxs(_Fragment, { children: [error && _jsx(Alert, { children: error }), _jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold mb-2", children: "People with access" }), members.length === 0 ? (_jsx("p", { className: "text-sm text-text-muted", children: "No one else has access to this mailbox yet." })) : (_jsx("ul", { className: "flex flex-col gap-2", children: members.map((member) => (_jsxs("li", { className: "flex items-center justify-between gap-3 text-sm py-1.5 px-3 bg-surface-alt rounded-sm", children: [_jsx("span", { className: "truncate", children: member.userOrRoleId }), _jsxs("span", { className: "flex items-center gap-2 shrink-0", children: [_jsxs("select", { "aria-label": `Role for ${member.userOrRoleId}`, className: "text-sm border border-border rounded-sm py-1 px-2 bg-surface", value: member.role, disabled: pendingRoleChange === member.userOrRoleId, onChange: (e) => handleRoleChange(member.userOrRoleId, e.target.value), children: [member.role === "custom" && (_jsx("option", { value: "custom", disabled: true, children: "Custom access" })), Object.keys(ROLE_LABELS).map((role) => (_jsx("option", { value: role, children: ROLE_LABELS[role] }, role)))] }), _jsx(Button, { type: "button", variant: "text", className: "!w-auto text-danger", onClick: () => setRemoveTarget(member), children: "Remove" })] })] }, member.userOrRoleId))) }))] }), _jsxs("form", { onSubmit: handleAdd, className: "flex flex-col gap-2", children: [_jsx("h2", { className: "text-sm font-semibold", children: "Add someone" }), addError && _jsx(Alert, { children: addError }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { type: "email", "aria-label": "Email address", placeholder: "Email address", className: "flex-1 text-sm border border-border rounded-sm py-1.5 px-2 bg-surface", value: emailInput, onChange: (e) => setEmailInput(e.target.value), disabled: adding }), _jsx("select", { "aria-label": "Role to grant", className: "text-sm border border-border rounded-sm py-1.5 px-2 bg-surface", value: newRole, onChange: (e) => setNewRole(e.target.value), disabled: adding, children: Object.keys(ROLE_LABELS).map((role) => (_jsx("option", { value: role, children: ROLE_LABELS[role] }, role))) }), _jsx(Button, { type: "submit", loading: adding, disabled: adding, className: "!w-auto", children: "Add" })] })] })] })), _jsxs(Modal, { open: !!removeTarget, onClose: closeRemoveModal, title: "Remove access", children: [_jsxs("p", { className: "text-sm mb-5", children: [removeTarget?.userOrRoleId, " will no longer be able to access ", mailbox?.displayName ?? "this mailbox", "."] }), _jsxs("div", { className: "flex gap-3 justify-end", children: [_jsx(Button, { type: "button", variant: "secondary", className: "!w-auto", disabled: removing, onClick: closeRemoveModal, children: "Cancel" }), _jsx(Button, { type: "button", className: "!w-auto !bg-none !bg-danger !border-danger hover:!bg-danger", loading: removing, disabled: removing, onClick: handleRemove, children: "Remove" })] })] })] }) }));
124
125
  }
126
+ export default routedPage("/settings/sharing", SettingsSharingPage);
@@ -1,8 +1,8 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
2
  export type SignatureDetailPageProps = Omit<SettingsShellProps, "active"> & {
4
3
  params: {
5
4
  uid: string;
6
5
  };
7
6
  };
8
- export default function SignatureDetailPage(props: SignatureDetailPageProps): React.JSX.Element;
7
+ declare const _default: import("../../../shared/navigation/AppRouter.js").RoutedPageComponent<SignatureDetailPageProps>;
8
+ export default _default;
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../_routedPage.js";
6
7
  import { useEffect, useState } from "react";
7
8
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
9
  import { getMailSignature, listMailSignatures, updateMailSignature } from "@rapidmx/react-shared/mail/mailSignaturesApi.js";
@@ -18,7 +19,7 @@ const INPUT_CLASS = "w-full text-sm py-2.5 px-3 border border-border rounded-sm
18
19
  async function handleUploadImage() {
19
20
  return null;
20
21
  }
21
- export default function SignatureDetailPage(props) {
22
+ function SignatureDetailPage(props) {
22
23
  return (_jsx(SettingsShell, { ...props, active: "signatures", children: _jsx(SignatureDetailContent, { uid: props.params.uid }) }));
23
24
  }
24
25
  function SignatureDetailContent({ uid }) {
@@ -94,3 +95,4 @@ function SignatureDetailContent({ uid }) {
94
95
  }
95
96
  return (_jsx("div", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: _jsxs("div", { className: "max-w-3xl", children: [_jsx("a", { href: `/settings/signatures?mailboxUid=${encodeURIComponent(mailboxUid)}`, className: "text-sm text-primary-dark hover:underline", children: "\u2190 All signatures" }), _jsx("h1", { className: "text-lg font-bold tracking-tight mt-1 mb-5", children: original.name }), error && _jsx(Alert, { children: error }), saved && !error && _jsx("div", { className: "mb-4 text-sm text-success font-medium", children: "Saved." }), _jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-5", children: [_jsxs("div", { className: "bg-surface border border-border rounded-md p-6 flex flex-col gap-4", children: [_jsx(FormField, { label: "Name", htmlFor: "name", children: _jsx("input", { id: "name", type: "text", className: INPUT_CLASS, value: name, onChange: (e) => setName(e.target.value) }) }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: isDefaultForNewMessages, onChange: (e) => setIsDefaultForNewMessages(e.target.checked) }), "Use for new messages"] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: isDefaultForReplyForward, onChange: (e) => setIsDefaultForReplyForward(e.target.checked) }), "Use for replies and forwards"] })] }), _jsx("div", { className: "h-64", children: _jsx(RichTextEditor, { value: contentHtml, onChange: setContentHtml, fill: true, onUploadImage: handleUploadImage }) }), _jsx("div", { children: _jsx(Button, { type: "submit", loading: saving, disabled: saving, className: "!w-auto", children: "Save changes" }) })] })] }) }));
96
97
  }
98
+ export default routedPage("/settings/signatures/:uid", SignatureDetailPage);
@@ -1,4 +1,4 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
3
2
  export type SettingsSignaturesPageProps = Omit<SettingsShellProps, "active">;
4
- export default function SettingsSignaturesPage(props: SettingsSignaturesPageProps): React.JSX.Element;
3
+ declare const _default: import("../../../shared/navigation/AppRouter.js").RoutedPageComponent<SettingsSignaturesPageProps>;
4
+ export default _default;
@@ -3,13 +3,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../_routedPage.js";
6
7
  import { useEffect, useState } from "react";
7
8
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
9
  import { listMailSignatures } from "@rapidmx/react-shared/mail/mailSignaturesApi.js";
9
10
  import SettingsShell, { useSettingsShell } from "../../../shared/components/settings/layout/SettingsShell.js";
10
11
  import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
11
12
  import Button from "@rapidmx/react-shared/components/buttons/Button.js";
12
- export default function SettingsSignaturesPage(props) {
13
+ function SettingsSignaturesPage(props) {
13
14
  return (_jsx(SettingsShell, { ...props, active: "signatures", children: _jsx(SignaturesContent, {}) }));
14
15
  }
15
16
  function SignaturesContent() {
@@ -32,3 +33,4 @@ function SignaturesContent() {
32
33
  .filter(Boolean)
33
34
  .join(" · ") }))] }), _jsx("a", { href: `/settings/signatures/${encodeURIComponent(sig.uid)}?mailboxUid=${encodeURIComponent(mailboxUid)}`, className: "text-primary-dark hover:underline font-medium text-sm", children: "Edit" })] }, sig.uid))) }))] }) }));
34
35
  }
36
+ export default routedPage("/settings/signatures", SettingsSignaturesPage);
@@ -1,4 +1,4 @@
1
- import React from "react";
2
1
  import { SettingsShellProps } from "../../../../shared/components/settings/layout/SettingsShell.js";
3
2
  export type NewSignaturePageProps = Omit<SettingsShellProps, "active">;
4
- export default function NewSignaturePage(props: NewSignaturePageProps): React.JSX.Element;
3
+ declare const _default: import("../../../../shared/navigation/AppRouter.js").RoutedPageComponent<NewSignaturePageProps>;
4
+ export default _default;
@@ -3,6 +3,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  // Copyright (C) 2026 Jean-Philippe Steinmetz
4
4
  // SPDX-License-Identifier: MPL-2.0
5
5
  ///////////////////////////////////////////////////////////////////////////////
6
+ import { routedPage } from "../../../_routedPage.js";
7
+ import { useNavigate } from "../../../../shared/navigation/AppRouter.js";
6
8
  import { useState } from "react";
7
9
  import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
10
  import { createMailSignature, listMailSignatures } from "@rapidmx/react-shared/mail/mailSignaturesApi.js";
@@ -13,7 +15,7 @@ import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
13
15
  import Button from "@rapidmx/react-shared/components/buttons/Button.js";
14
16
  import FormField from "@rapidmx/react-shared/components/forms/FormField.js";
15
17
  const INPUT_CLASS = "w-full text-sm py-2.5 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
16
- export default function NewSignaturePage(props) {
18
+ function NewSignaturePage(props) {
17
19
  return (_jsx(SettingsShell, { ...props, active: "signatures", children: _jsx(NewSignatureForm, {}) }));
18
20
  }
19
21
  /** Signatures aren't backed by a draft/attachment record the way Compose's own inline images are (see
@@ -23,6 +25,7 @@ async function handleUploadImage() {
23
25
  return null;
24
26
  }
25
27
  function NewSignatureForm() {
28
+ const navigate = useNavigate();
26
29
  const { mailboxUid } = useSettingsShell();
27
30
  const [name, setName] = useState("");
28
31
  const [contentHtml, setContentHtml] = useState("");
@@ -50,7 +53,7 @@ function NewSignatureForm() {
50
53
  isDefaultForNewMessages,
51
54
  isDefaultForReplyForward,
52
55
  });
53
- window.location.href = `/settings/signatures/${encodeURIComponent(created.uid)}?mailboxUid=${encodeURIComponent(mailboxUid)}`;
56
+ navigate(`/settings/signatures/${encodeURIComponent(created.uid)}?mailboxUid=${encodeURIComponent(mailboxUid)}`);
54
57
  }
55
58
  catch (err) {
56
59
  setError(err instanceof ApiRequestError ? err.message : "Could not create the signature.");
@@ -61,3 +64,4 @@ function NewSignatureForm() {
61
64
  }
62
65
  return (_jsx("div", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: _jsxs("div", { className: "max-w-3xl", children: [_jsx("h1", { className: "text-lg font-bold tracking-tight mb-5", children: "New signature" }), error && _jsx(Alert, { children: error }), _jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-5", children: [_jsxs("div", { className: "bg-surface border border-border rounded-md p-6 flex flex-col gap-4", children: [_jsx(FormField, { label: "Name", htmlFor: "name", children: _jsx("input", { id: "name", type: "text", className: INPUT_CLASS, value: name, onChange: (e) => setName(e.target.value), placeholder: "Work signature" }) }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: isDefaultForNewMessages, onChange: (e) => setIsDefaultForNewMessages(e.target.checked) }), "Use for new messages"] }), _jsxs("label", { className: "flex items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", checked: isDefaultForReplyForward, onChange: (e) => setIsDefaultForReplyForward(e.target.checked) }), "Use for replies and forwards"] })] }), _jsx("div", { className: "h-64", children: _jsx(RichTextEditor, { value: contentHtml, onChange: setContentHtml, fill: true, onUploadImage: handleUploadImage }) }), _jsxs("div", { className: "flex gap-3", children: [_jsx(Button, { type: "submit", loading: saving, disabled: saving, className: "!w-auto", children: "Create signature" }), _jsx("a", { href: `/settings/signatures?mailboxUid=${encodeURIComponent(mailboxUid)}`, children: _jsx(Button, { type: "button", variant: "secondary", className: "!w-auto", children: "Cancel" }) })] })] })] }) }));
63
66
  }
67
+ export default routedPage("/settings/signatures/new", NewSignaturePage);
@@ -1,3 +1,3 @@
1
- import React from "react";
2
1
  import { TasksShellProps } from "../../shared/components/tasks/layout/TasksShell.js";
3
- export default function TasksPage(props: TasksShellProps): React.JSX.Element;
2
+ declare const _default: import("../../shared/navigation/AppRouter.js").RoutedPageComponent<TasksShellProps>;
3
+ export default _default;