@rapidmx/web-client 0.10.0 → 0.12.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.
- package/README.md +183 -2
- package/apps/admin/_layout.tsx +8 -2
- package/apps/admin/index.tsx +7 -1
- package/apps/admin/ingest-queue/index.tsx +2 -1
- package/apps/admin/mailboxes/[uid].tsx +23 -10
- package/apps/admin/mailboxes/new/index.tsx +3 -3
- package/apps/admin/quarantine/index.tsx +2 -1
- package/apps/admin/signing-certificates/index.tsx +343 -0
- package/apps/escrow/_layout.tsx +8 -2
- package/apps/shared/appearance/AppearanceForm.tsx +392 -0
- package/apps/shared/appearance/AppearanceHead.tsx +49 -0
- package/apps/shared/appearance/AppearanceProvider.tsx +470 -0
- package/apps/shared/appearance/ColorField.tsx +107 -0
- package/apps/shared/appearance/appearanceCache.ts +106 -0
- package/apps/shared/appearance/appearanceContext.ts +77 -0
- package/apps/shared/appearance/bootScript.ts +35 -0
- package/apps/shared/appearance/color.ts +169 -0
- package/apps/shared/appearance/photo.ts +88 -0
- package/apps/shared/appearance/resolvedTheme.ts +67 -0
- package/apps/shared/appearance/theme.ts +355 -0
- package/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.tsx +4 -4
- package/apps/shared/components/admin/layout/AdminShell.tsx +22 -10
- package/apps/shared/components/admin/mailboxes/ShareAccessCard.tsx +107 -60
- package/apps/shared/components/admin/settings/BrandingForm.tsx +24 -0
- package/apps/shared/components/admin/settings/DomainDnsSetup.tsx +60 -14
- package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +65 -16
- package/apps/shared/components/admin/settings/PluginsManager.tsx +228 -25
- package/apps/shared/components/admin/setup/SetupWizard.tsx +2 -1
- package/apps/shared/components/calendar/CalendarListSidebar.tsx +4 -5
- package/apps/shared/components/contacts/ContactForm.tsx +11 -5
- package/apps/shared/components/contacts/ContactsSidebar.tsx +5 -3
- package/apps/shared/components/contacts/ContactsToolbar.tsx +25 -52
- package/apps/shared/components/contacts/layout/ContactsShell.tsx +10 -5
- package/apps/shared/components/escrow/layout/EscrowShell.tsx +13 -6
- package/apps/shared/components/layout/AppShell.tsx +98 -32
- package/apps/shared/components/layout/BrandingChrome.tsx +200 -13
- package/apps/shared/components/layout/RailIcon.tsx +100 -0
- package/apps/shared/components/layout/ResponsiveToolbar.tsx +315 -0
- package/apps/shared/components/layout/ThemeSwitch.tsx +84 -0
- package/apps/shared/components/layout/UserMenu.tsx +75 -6
- package/apps/shared/components/mail/ConversationList.tsx +4 -2
- package/apps/shared/components/mail/ConversationThreadPane.tsx +487 -475
- package/apps/shared/components/mail/LazyReadingPane.tsx +14 -16
- package/apps/shared/components/mail/MailSelectionBar.tsx +2 -10
- package/apps/shared/components/mail/MessageDetailPane.tsx +366 -287
- package/apps/shared/components/mail/OutboxBadge.tsx +44 -0
- package/apps/shared/components/mail/OutboxRowStatus.tsx +31 -0
- package/apps/shared/components/mail/compose/ComposeContext.tsx +35 -2
- package/apps/shared/components/mail/compose/ComposeWindow.tsx +239 -437
- package/apps/shared/components/mail/compose/encryptionRequirement.ts +86 -0
- package/apps/shared/components/mail/layout/MailShell.tsx +39 -25
- package/apps/shared/components/mail/reading/EncryptedBody.tsx +65 -0
- package/apps/shared/components/mail/reading/EncryptedPreview.tsx +35 -0
- package/apps/shared/components/mail/reading/MessageBody.tsx +240 -0
- package/apps/shared/components/mail/reading/MessageCard.tsx +174 -0
- package/apps/shared/components/mail/reading/bodyContent.ts +100 -0
- package/apps/shared/components/mail/reading/bodyHtml.ts +298 -0
- package/apps/shared/components/mail/reading/color.ts +245 -0
- package/apps/shared/components/mail/reading/frameControl.ts +142 -0
- package/apps/shared/components/mail/reading/frameDocument.ts +123 -0
- package/apps/shared/components/mail/reading/safeDocument.ts +24 -0
- package/apps/shared/components/mail/reading/themeAdaptation.ts +221 -0
- package/apps/shared/components/mail/reading/themeSurface.ts +90 -0
- package/apps/shared/components/mail/reading/viewOriginal.ts +38 -0
- package/apps/shared/components/settings/SigningCertificateCard.tsx +344 -0
- package/apps/shared/components/settings/layout/SettingsShell.tsx +1 -0
- package/apps/shared/components/sharing/PrincipalListField.tsx +82 -0
- package/apps/shared/components/sharing/PrincipalPicker.tsx +76 -0
- package/apps/shared/components/sharing/PrincipalResolver.tsx +164 -0
- package/apps/shared/components/tasks/TasksSidebar.tsx +5 -3
- package/apps/shared/components/tasks/layout/TasksShell.tsx +9 -5
- package/apps/shared/mail/folderCounts.ts +9 -3
- package/apps/shared/mail/folderTree.ts +143 -0
- package/apps/shared/mail/outbox/UnlockBridge.tsx +23 -0
- package/apps/shared/mail/outbox/composeBridge.ts +69 -0
- package/apps/shared/mail/outbox/outboxState.ts +88 -0
- package/apps/shared/mail/outbox/pendingSends.ts +146 -0
- package/apps/shared/mail/outbox/sendDecision.ts +157 -0
- package/apps/shared/mail/outbox/sendJob.ts +427 -0
- package/apps/shared/mail/outbox/sendOutcomes.ts +146 -0
- package/apps/shared/mail/outbox/sendState.ts +35 -0
- package/apps/shared/mail/outbox/useOutboxStatus.ts +61 -0
- package/apps/shared/mail/useMailConnection.ts +81 -28
- package/apps/shared/mail/useMailLiveUpdates.ts +55 -10
- package/apps/shared/mail/useNewMailNotifications.ts +47 -32
- package/apps/shared/navigation/AppRouter.tsx +2 -2
- package/apps/shared/notifications/NotificationCenter.tsx +215 -0
- package/apps/shared/notifications/NotificationHistoryDialog.tsx +90 -0
- package/apps/shared/notifications/apiErrors.ts +98 -0
- package/apps/shared/notifications/headerOffset.ts +35 -0
- package/apps/shared/notifications/pushStatus.ts +56 -0
- package/apps/shared/notifications/store.ts +549 -0
- package/apps/shared/notifications/systemErrors.ts +63 -0
- package/apps/shared/notifications/useNotifications.ts +41 -0
- package/apps/shared/signing/enrollmentStorage.ts +33 -0
- package/apps/shared/signing/enrollmentTracker.ts +385 -0
- package/apps/shared/signing/enrollmentView.ts +251 -0
- package/apps/shared/signing/signingInfo.ts +58 -0
- package/apps/shared/signing/useNow.ts +19 -0
- package/apps/shared/signing/useSigningEnrollmentWatcher.ts +90 -0
- package/apps/shared/styles/app.css +80 -0
- package/apps/www/_layout.tsx +8 -2
- package/apps/www/_routes.ts +1 -0
- package/apps/www/calendar/index.tsx +9 -14
- package/apps/www/contacts/[uid].tsx +5 -8
- package/apps/www/contacts/index.tsx +587 -584
- package/apps/www/index.tsx +38 -27
- package/apps/www/messages/[uid].tsx +3 -1
- package/apps/www/settings/appearance/index.tsx +21 -0
- package/apps/www/settings/auto-reply/index.tsx +3 -7
- package/apps/www/settings/encryption/index.tsx +151 -116
- package/apps/www/settings/filters/[uid].tsx +3 -1
- package/apps/www/settings/filters/new/index.tsx +3 -1
- package/apps/www/settings/privacy/index.tsx +3 -8
- package/apps/www/settings/read-receipts/index.tsx +3 -7
- package/apps/www/settings/sharing/index.tsx +44 -65
- package/apps/www/settings/signatures/[uid].tsx +3 -1
- package/apps/www/settings/signatures/new/index.tsx +3 -2
- package/apps/www/tasks/index.tsx +11 -16
- package/dist/apps/admin/_layout.d.ts +5 -1
- package/dist/apps/admin/_layout.js +3 -2
- package/dist/apps/admin/index.js +3 -2
- package/dist/apps/admin/ingest-queue/index.js +2 -1
- package/dist/apps/admin/mailboxes/[uid].js +9 -6
- package/dist/apps/admin/mailboxes/new/index.js +1 -1
- package/dist/apps/admin/quarantine/index.js +2 -1
- package/dist/apps/admin/signing-certificates/index.d.ts +3 -0
- package/dist/apps/admin/signing-certificates/index.js +161 -0
- package/dist/apps/escrow/_layout.d.ts +5 -1
- package/dist/apps/escrow/_layout.js +3 -2
- package/dist/apps/shared/appearance/AppearanceForm.d.ts +7 -0
- package/dist/apps/shared/appearance/AppearanceForm.js +131 -0
- package/dist/apps/shared/appearance/AppearanceHead.d.ts +15 -0
- package/dist/apps/shared/appearance/AppearanceHead.js +31 -0
- package/dist/apps/shared/appearance/AppearanceProvider.d.ts +32 -0
- package/dist/apps/shared/appearance/AppearanceProvider.js +390 -0
- package/dist/apps/shared/appearance/ColorField.d.ts +22 -0
- package/dist/apps/shared/appearance/ColorField.js +40 -0
- package/dist/apps/shared/appearance/appearanceCache.d.ts +45 -0
- package/dist/apps/shared/appearance/appearanceCache.js +80 -0
- package/dist/apps/shared/appearance/appearanceContext.d.ts +45 -0
- package/dist/apps/shared/appearance/appearanceContext.js +29 -0
- package/dist/apps/shared/appearance/bootScript.d.ts +16 -0
- package/dist/apps/shared/appearance/bootScript.js +33 -0
- package/dist/apps/shared/appearance/color.d.ts +65 -0
- package/dist/apps/shared/appearance/color.js +132 -0
- package/dist/apps/shared/appearance/photo.d.ts +17 -0
- package/dist/apps/shared/appearance/photo.js +79 -0
- package/dist/apps/shared/appearance/resolvedTheme.d.ts +21 -0
- package/dist/apps/shared/appearance/resolvedTheme.js +55 -0
- package/dist/apps/shared/appearance/theme.d.ts +111 -0
- package/dist/apps/shared/appearance/theme.js +251 -0
- package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js +3 -2
- package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +1 -1
- package/dist/apps/shared/components/admin/layout/AdminShell.js +16 -6
- package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.d.ts +10 -5
- package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +49 -34
- package/dist/apps/shared/components/admin/settings/BrandingForm.d.ts +2 -0
- package/dist/apps/shared/components/admin/settings/BrandingForm.js +7 -1
- package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +25 -5
- package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +18 -7
- package/dist/apps/shared/components/admin/settings/PluginsManager.js +106 -20
- package/dist/apps/shared/components/admin/setup/SetupWizard.js +2 -1
- package/dist/apps/shared/components/calendar/CalendarListSidebar.js +8 -8
- package/dist/apps/shared/components/contacts/ContactForm.js +1 -1
- package/dist/apps/shared/components/contacts/ContactsSidebar.js +4 -2
- package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +3 -1
- package/dist/apps/shared/components/contacts/ContactsToolbar.js +24 -9
- package/dist/apps/shared/components/contacts/layout/ContactsShell.js +4 -1
- package/dist/apps/shared/components/escrow/layout/EscrowShell.js +7 -4
- package/dist/apps/shared/components/layout/AppShell.d.ts +6 -1
- package/dist/apps/shared/components/layout/AppShell.js +59 -13
- package/dist/apps/shared/components/layout/BrandingChrome.d.ts +69 -10
- package/dist/apps/shared/components/layout/BrandingChrome.js +140 -12
- package/dist/apps/shared/components/layout/RailIcon.d.ts +21 -0
- package/dist/apps/shared/components/layout/RailIcon.js +85 -0
- package/dist/apps/shared/components/layout/ResponsiveToolbar.d.ts +55 -0
- package/dist/apps/shared/components/layout/ResponsiveToolbar.js +199 -0
- package/dist/apps/shared/components/layout/ThemeSwitch.d.ts +9 -0
- package/dist/apps/shared/components/layout/ThemeSwitch.js +54 -0
- package/dist/apps/shared/components/layout/UserMenu.d.ts +7 -1
- package/dist/apps/shared/components/layout/UserMenu.js +41 -7
- package/dist/apps/shared/components/mail/ConversationList.js +3 -2
- package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +2 -1
- package/dist/apps/shared/components/mail/ConversationThreadPane.js +42 -20
- package/dist/apps/shared/components/mail/LazyReadingPane.js +9 -8
- package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +3 -4
- package/dist/apps/shared/components/mail/MailSelectionBar.js +2 -3
- package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +18 -7
- package/dist/apps/shared/components/mail/MessageDetailPane.js +86 -41
- package/dist/apps/shared/components/mail/OutboxBadge.d.ts +17 -0
- package/dist/apps/shared/components/mail/OutboxBadge.js +18 -0
- package/dist/apps/shared/components/mail/OutboxRowStatus.d.ts +10 -0
- package/dist/apps/shared/components/mail/OutboxRowStatus.js +19 -0
- package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +8 -0
- package/dist/apps/shared/components/mail/compose/ComposeContext.js +28 -3
- package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +2 -1
- package/dist/apps/shared/components/mail/compose/ComposeWindow.js +229 -328
- package/dist/apps/shared/components/mail/compose/encryptionRequirement.d.ts +49 -0
- package/dist/apps/shared/components/mail/compose/encryptionRequirement.js +35 -0
- package/dist/apps/shared/components/mail/layout/MailShell.d.ts +2 -0
- package/dist/apps/shared/components/mail/layout/MailShell.js +20 -14
- package/dist/apps/shared/components/mail/reading/EncryptedBody.d.ts +21 -0
- package/dist/apps/shared/components/mail/reading/EncryptedBody.js +22 -0
- package/dist/apps/shared/components/mail/reading/EncryptedPreview.d.ts +18 -0
- package/dist/apps/shared/components/mail/reading/EncryptedPreview.js +22 -0
- package/dist/apps/shared/components/mail/reading/MessageBody.d.ts +32 -0
- package/dist/apps/shared/components/mail/reading/MessageBody.js +136 -0
- package/dist/apps/shared/components/mail/reading/MessageCard.d.ts +62 -0
- package/dist/apps/shared/components/mail/reading/MessageCard.js +58 -0
- package/dist/apps/shared/components/mail/reading/bodyContent.d.ts +38 -0
- package/dist/apps/shared/components/mail/reading/bodyContent.js +84 -0
- package/dist/apps/shared/components/mail/reading/bodyHtml.d.ts +47 -0
- package/dist/apps/shared/components/mail/reading/bodyHtml.js +267 -0
- package/dist/apps/shared/components/mail/reading/color.d.ts +63 -0
- package/dist/apps/shared/components/mail/reading/color.js +201 -0
- package/dist/apps/shared/components/mail/reading/frameControl.d.ts +33 -0
- package/dist/apps/shared/components/mail/reading/frameControl.js +120 -0
- package/dist/apps/shared/components/mail/reading/frameDocument.d.ts +52 -0
- package/dist/apps/shared/components/mail/reading/frameDocument.js +98 -0
- package/dist/apps/shared/components/mail/reading/safeDocument.d.ts +3 -0
- package/dist/apps/shared/components/mail/reading/safeDocument.js +12 -0
- package/dist/apps/shared/components/mail/reading/themeAdaptation.d.ts +56 -0
- package/dist/apps/shared/components/mail/reading/themeAdaptation.js +144 -0
- package/dist/apps/shared/components/mail/reading/themeSurface.d.ts +17 -0
- package/dist/apps/shared/components/mail/reading/themeSurface.js +83 -0
- package/dist/apps/shared/components/mail/reading/viewOriginal.d.ts +9 -0
- package/dist/apps/shared/components/mail/reading/viewOriginal.js +32 -0
- package/dist/apps/shared/components/settings/SigningCertificateCard.d.ts +32 -0
- package/dist/apps/shared/components/settings/SigningCertificateCard.js +98 -0
- package/dist/apps/shared/components/settings/layout/SettingsShell.js +1 -0
- package/dist/apps/shared/components/sharing/PrincipalListField.d.ts +24 -0
- package/dist/apps/shared/components/sharing/PrincipalListField.js +23 -0
- package/dist/apps/shared/components/sharing/PrincipalPicker.d.ts +28 -0
- package/dist/apps/shared/components/sharing/PrincipalPicker.js +24 -0
- package/dist/apps/shared/components/sharing/PrincipalResolver.d.ts +44 -0
- package/dist/apps/shared/components/sharing/PrincipalResolver.js +92 -0
- package/dist/apps/shared/components/tasks/TasksSidebar.js +4 -2
- package/dist/apps/shared/components/tasks/layout/TasksShell.js +3 -1
- package/dist/apps/shared/mail/folderCounts.d.ts +1 -1
- package/dist/apps/shared/mail/folderCounts.js +9 -3
- package/dist/apps/shared/mail/folderTree.d.ts +55 -0
- package/dist/apps/shared/mail/folderTree.js +116 -0
- package/dist/apps/shared/mail/outbox/UnlockBridge.d.ts +5 -0
- package/dist/apps/shared/mail/outbox/UnlockBridge.js +18 -0
- package/dist/apps/shared/mail/outbox/composeBridge.d.ts +34 -0
- package/dist/apps/shared/mail/outbox/composeBridge.js +32 -0
- package/dist/apps/shared/mail/outbox/outboxState.d.ts +41 -0
- package/dist/apps/shared/mail/outbox/outboxState.js +42 -0
- package/dist/apps/shared/mail/outbox/pendingSends.d.ts +39 -0
- package/dist/apps/shared/mail/outbox/pendingSends.js +109 -0
- package/dist/apps/shared/mail/outbox/sendDecision.d.ts +80 -0
- package/dist/apps/shared/mail/outbox/sendDecision.js +94 -0
- package/dist/apps/shared/mail/outbox/sendJob.d.ts +68 -0
- package/dist/apps/shared/mail/outbox/sendJob.js +319 -0
- package/dist/apps/shared/mail/outbox/sendOutcomes.d.ts +3 -0
- package/dist/apps/shared/mail/outbox/sendOutcomes.js +141 -0
- package/dist/apps/shared/mail/outbox/sendState.d.ts +25 -0
- package/dist/apps/shared/mail/outbox/sendState.js +8 -0
- package/dist/apps/shared/mail/outbox/useOutboxStatus.d.ts +11 -0
- package/dist/apps/shared/mail/outbox/useOutboxStatus.js +49 -0
- package/dist/apps/shared/mail/useMailConnection.d.ts +9 -8
- package/dist/apps/shared/mail/useMailConnection.js +64 -22
- package/dist/apps/shared/mail/useMailLiveUpdates.d.ts +17 -4
- package/dist/apps/shared/mail/useMailLiveUpdates.js +36 -10
- package/dist/apps/shared/mail/useNewMailNotifications.d.ts +4 -10
- package/dist/apps/shared/mail/useNewMailNotifications.js +43 -23
- package/dist/apps/shared/navigation/AppRouter.js +2 -2
- package/dist/apps/shared/notifications/NotificationCenter.d.ts +19 -0
- package/dist/apps/shared/notifications/NotificationCenter.js +90 -0
- package/dist/apps/shared/notifications/NotificationHistoryDialog.d.ts +10 -0
- package/dist/apps/shared/notifications/NotificationHistoryDialog.js +36 -0
- package/dist/apps/shared/notifications/apiErrors.d.ts +19 -0
- package/dist/apps/shared/notifications/apiErrors.js +86 -0
- package/dist/apps/shared/notifications/headerOffset.d.ts +8 -0
- package/dist/apps/shared/notifications/headerOffset.js +33 -0
- package/dist/apps/shared/notifications/pushStatus.d.ts +9 -0
- package/dist/apps/shared/notifications/pushStatus.js +54 -0
- package/dist/apps/shared/notifications/store.d.ts +136 -0
- package/dist/apps/shared/notifications/store.js +416 -0
- package/dist/apps/shared/notifications/systemErrors.d.ts +9 -0
- package/dist/apps/shared/notifications/systemErrors.js +58 -0
- package/dist/apps/shared/notifications/useNotifications.d.ts +17 -0
- package/dist/apps/shared/notifications/useNotifications.js +18 -0
- package/dist/apps/shared/signing/enrollmentStorage.d.ts +10 -0
- package/dist/apps/shared/signing/enrollmentStorage.js +33 -0
- package/dist/apps/shared/signing/enrollmentTracker.d.ts +73 -0
- package/dist/apps/shared/signing/enrollmentTracker.js +307 -0
- package/dist/apps/shared/signing/enrollmentView.d.ts +57 -0
- package/dist/apps/shared/signing/enrollmentView.js +214 -0
- package/dist/apps/shared/signing/signingInfo.d.ts +11 -0
- package/dist/apps/shared/signing/signingInfo.js +48 -0
- package/dist/apps/shared/signing/useNow.d.ts +2 -0
- package/dist/apps/shared/signing/useNow.js +18 -0
- package/dist/apps/shared/signing/useSigningEnrollmentWatcher.d.ts +16 -0
- package/dist/apps/shared/signing/useSigningEnrollmentWatcher.js +87 -0
- package/dist/apps/shared/styles/app.css +80 -0
- package/dist/apps/www/_layout.d.ts +5 -1
- package/dist/apps/www/_layout.js +3 -2
- package/dist/apps/www/_routes.js +1 -0
- package/dist/apps/www/calendar/index.js +3 -4
- package/dist/apps/www/contacts/[uid].js +5 -7
- package/dist/apps/www/contacts/index.js +14 -21
- package/dist/apps/www/index.js +37 -19
- package/dist/apps/www/messages/[uid].js +3 -1
- package/dist/apps/www/settings/appearance/index.d.ts +4 -0
- package/dist/apps/www/settings/appearance/index.js +13 -0
- package/dist/apps/www/settings/auto-reply/index.js +3 -6
- package/dist/apps/www/settings/encryption/index.js +103 -95
- package/dist/apps/www/settings/filters/[uid].js +3 -1
- package/dist/apps/www/settings/filters/new/index.js +3 -1
- package/dist/apps/www/settings/privacy/index.js +5 -8
- package/dist/apps/www/settings/read-receipts/index.js +3 -6
- package/dist/apps/www/settings/sharing/index.js +19 -33
- package/dist/apps/www/settings/signatures/[uid].js +3 -1
- package/dist/apps/www/settings/signatures/new/index.js +3 -2
- package/dist/apps/www/tasks/index.js +8 -14
- package/package.json +2 -2
- package/apps/shared/components/mail/NewMailToasts.tsx +0 -141
- package/apps/shared/components/mail/compose/SendFailureAlert.tsx +0 -48
- package/dist/apps/shared/components/mail/NewMailToasts.d.ts +0 -19
- package/dist/apps/shared/components/mail/NewMailToasts.js +0 -55
- package/dist/apps/shared/components/mail/compose/SendFailureAlert.d.ts +0 -14
- package/dist/apps/shared/components/mail/compose/SendFailureAlert.js +0 -11
package/dist/apps/www/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { prefetchComposeWindow } from "../shared/components/mail/compose/Compose
|
|
|
10
10
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
11
11
|
import { HiOutlineFlag, HiOutlineLockClosed, HiOutlinePaperClip } from "react-icons/hi2";
|
|
12
12
|
import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
|
|
13
|
-
import { archiveMessage, bulkUpdateMessages, createFolder, getMessage, getMessageRawContent, listMessages, moveMessages, setMessagesFlagged, } from "@rapidmx/react-shared/mail/mailApi.js";
|
|
13
|
+
import { archiveMessage, bulkUpdateMessages, createFolder, getMessage, getMessageRawContent, listFolders, listMessages, moveMessages, setMessagesFlagged, } from "@rapidmx/react-shared/mail/mailApi.js";
|
|
14
14
|
import { listLabels } from "@rapidmx/react-shared/mail/labelsApi.js";
|
|
15
15
|
import { listConversationMessages, listConversations, } from "@rapidmx/react-shared/mail/conversationsApi.js";
|
|
16
16
|
import { search as searchMailbox } from "@rapidmx/react-shared/search/searchApi.js";
|
|
@@ -22,6 +22,7 @@ import { useMessageAttachments } from "@rapidmx/react-shared/mail/mailDetailHook
|
|
|
22
22
|
import useIsMobile from "@rapidmx/react-shared/util/useIsMobile.js";
|
|
23
23
|
import MailShell, { useMailShell, } from "../shared/components/mail/layout/MailShell.js";
|
|
24
24
|
import MailAddress from "../shared/components/mail/MailAddress.js";
|
|
25
|
+
import OutboxRowStatus from "../shared/components/mail/OutboxRowStatus.js";
|
|
25
26
|
import { mergeFirstPage } from "../shared/mail/mergeFirstPage.js";
|
|
26
27
|
import { listSnapshotKey, readListSnapshot, saveListScroll, writeListSnapshot } from "../shared/mail/listSnapshots.js";
|
|
27
28
|
import { setReadStateMany } from "../shared/mail/messageReadState.js";
|
|
@@ -29,6 +30,7 @@ import { useMarkMessageRead } from "../shared/mail/useMarkMessageRead.js";
|
|
|
29
30
|
import { ROW_FOCUS_CLASS, UnreadBar, UnreadLabel, dateClass, isUnread, rowClass, senderClass, subjectClass } from "../shared/components/mail/unreadStyle.js";
|
|
30
31
|
import { LazyConversationThreadPane, LazyMessageDetailPane, prefetchReadingPane } from "../shared/components/mail/LazyReadingPane.js";
|
|
31
32
|
import ConversationList from "../shared/components/mail/ConversationList.js";
|
|
33
|
+
import { EncryptedPreview } from "../shared/components/mail/reading/EncryptedPreview.js";
|
|
32
34
|
import MailListToolbar from "../shared/components/mail/MailListToolbar.js";
|
|
33
35
|
import MailSelectionBar from "../shared/components/mail/MailSelectionBar.js";
|
|
34
36
|
import { CONVERSATION_SORT_NOTE, CONVERSATION_SORT_UNAVAILABLE, MAIL_LIST_CLASSIFICATION_FILTERS, getMailListPreferences, setMailListPreferences, sortConversations, } from "../shared/components/mail/listPreferences.js";
|
|
@@ -38,6 +40,7 @@ import { useUnlockPrompt } from "../shared/components/layout/UnlockPromptProvide
|
|
|
38
40
|
import { SHORTCUTS } from "../shared/keyboard/keymap.js";
|
|
39
41
|
import { isActivatable } from "../shared/keyboard/targets.js";
|
|
40
42
|
import { useShortcut } from "../shared/keyboard/useShortcut.js";
|
|
43
|
+
import { notifyApiError } from "../shared/notifications/apiErrors.js";
|
|
41
44
|
const MESSAGE_PAGE_SIZE = 50;
|
|
42
45
|
const SEARCH_DEBOUNCE_MS = 300;
|
|
43
46
|
const LIST_PREVIEW_MAX_LENGTH = 160;
|
|
@@ -351,7 +354,7 @@ function InboxPage(props) {
|
|
|
351
354
|
return (_jsx(MailShell, { ...props, children: _jsx(InboxContent, { userUid: props.userUid }) }));
|
|
352
355
|
}
|
|
353
356
|
function InboxContent({ userUid }) {
|
|
354
|
-
const { folderUid, mailboxUid, mailboxes, mailboxFolders, aggregateFolderType, onFolderCreated, live, trackMessageChange } = useMailShell();
|
|
357
|
+
const { folderUid, mailboxUid, mailboxes, mailboxFolders, aggregateFolderType, onFolderCreated, noteFolderUids, live, trackMessageChange } = useMailShell();
|
|
355
358
|
const isMobile = useIsMobile();
|
|
356
359
|
const navigate = useNavigate();
|
|
357
360
|
const { requestUnlock } = useUnlockPrompt();
|
|
@@ -393,7 +396,6 @@ function InboxContent({ userUid }) {
|
|
|
393
396
|
// or it would act on a selection that is still arriving.
|
|
394
397
|
const [resolvingSelection, setResolvingSelection] = useState(0);
|
|
395
398
|
const [bulkBusy, setBulkBusy] = useState(false);
|
|
396
|
-
const [bulkError, setBulkError] = useState(null);
|
|
397
399
|
// Bumped to force the list effect below to re-run - a bulk update is deliberately neither atomic nor
|
|
398
400
|
// all-or-nothing (see `bulkUpdateMessages()`), so a rejection means refetching rather than guessing
|
|
399
401
|
// which half of the selection actually landed.
|
|
@@ -980,9 +982,16 @@ function InboxContent({ userUid }) {
|
|
|
980
982
|
unlockRefresh,
|
|
981
983
|
searchAllMail,
|
|
982
984
|
aggregateFolderType,
|
|
983
|
-
|
|
985
|
+
// Only a merged view is built from the folder tree; for a single folder a folder appearing in the sidebar (the Outbox, Sent Items) must not reload
|
|
986
|
+
// the list on screen and forget its selection.
|
|
987
|
+
aggregateFolderType ? mailboxFolders : null,
|
|
984
988
|
activeMailboxUid,
|
|
985
989
|
]);
|
|
990
|
+
// Which folders the messages on screen live in: one the sidebar does not know (the Outbox and Sent Items are made by the server on first use) is looked for -
|
|
991
|
+
// its mailbox's folders are listed again, once - so it appears without a reload. A conversation names every folder it has a message in.
|
|
992
|
+
useEffect(() => {
|
|
993
|
+
noteFolderUids([...messages.map((message) => message.folderUid), ...conversations.flatMap((conversation) => conversation.folderUids)]);
|
|
994
|
+
}, [messages, conversations, noteFolderUids]);
|
|
986
995
|
// New mail without a reload. `live` is bumped by a push event, a reconnect, the safety-net poll or the tab coming back (see
|
|
987
996
|
// `useMailLiveUpdates()`); this then quietly refetches the first page of whatever is listed and folds it in - unlike the
|
|
988
997
|
// effect above it resets nothing: not the selection, the open thread, select mode, the scroll position or the rows
|
|
@@ -1290,7 +1299,6 @@ function InboxContent({ userUid }) {
|
|
|
1290
1299
|
setSelectMode(false);
|
|
1291
1300
|
setSelectedUids(new Set());
|
|
1292
1301
|
setSelectedConversationIds(new Set());
|
|
1293
|
-
setBulkError(null);
|
|
1294
1302
|
}
|
|
1295
1303
|
function toggleSelected(uid) {
|
|
1296
1304
|
setSelectedUids((prev) => {
|
|
@@ -1306,7 +1314,7 @@ function InboxContent({ userUid }) {
|
|
|
1306
1314
|
}
|
|
1307
1315
|
/** Loads (once) the messages behind each of `ids`, so a ticked conversation resolves to the messages
|
|
1308
1316
|
* every bulk action below acts on. If any of them fails to load, none of that batch stays ticked and
|
|
1309
|
-
*
|
|
1317
|
+
* a pop-up says why - better than acting on the part of a selection that happened to arrive. */
|
|
1310
1318
|
async function resolveConversations(ids) {
|
|
1311
1319
|
const missing = ids.filter((id) => !conversationMessagesById[id]);
|
|
1312
1320
|
if (missing.length === 0) {
|
|
@@ -1318,7 +1326,7 @@ function InboxContent({ userUid }) {
|
|
|
1318
1326
|
setConversationMessagesById((prev) => ({ ...prev, ...Object.fromEntries(loaded) }));
|
|
1319
1327
|
}
|
|
1320
1328
|
catch (err) {
|
|
1321
|
-
|
|
1329
|
+
notifyApiError(err, "Couldn't load the messages in one of those conversations");
|
|
1322
1330
|
setSelectedConversationIds((prev) => {
|
|
1323
1331
|
const next = new Set(prev);
|
|
1324
1332
|
for (const id of missing) {
|
|
@@ -1359,14 +1367,14 @@ function InboxContent({ userUid }) {
|
|
|
1359
1367
|
*
|
|
1360
1368
|
* A bulk update is applied element by element server-side and stops at its first rejection, so a
|
|
1361
1369
|
* failure leaves an unknown prefix of the selection already changed (see `bulkUpdateMessages()`) -
|
|
1362
|
-
* which is why a failure reloads the list rather than trying to reconcile it, and says so
|
|
1370
|
+
* which is why a failure reloads the list rather than trying to reconcile it, and says so ("all of those messages" in the pop-up's
|
|
1371
|
+
* title: some may have changed).
|
|
1363
1372
|
*
|
|
1364
1373
|
* `chosen` is the selection bar's ticked messages unless the caller (a keyboard shortcut acting on the one open message or conversation)
|
|
1365
1374
|
* names its own. Resolves whether it succeeded.
|
|
1366
1375
|
*/
|
|
1367
1376
|
async function runBulkAction(action, removesRows, chosen = selectedMessages) {
|
|
1368
1377
|
setBulkBusy(true);
|
|
1369
|
-
setBulkError(null);
|
|
1370
1378
|
try {
|
|
1371
1379
|
const updated = await action(chosen);
|
|
1372
1380
|
if (removesRows) {
|
|
@@ -1399,7 +1407,7 @@ function InboxContent({ userUid }) {
|
|
|
1399
1407
|
return true;
|
|
1400
1408
|
}
|
|
1401
1409
|
catch (err) {
|
|
1402
|
-
|
|
1410
|
+
notifyApiError(err, chosen.length === 1 ? "Couldn't update the message" : "Couldn't update all of those messages");
|
|
1403
1411
|
setSelectedUids(new Set());
|
|
1404
1412
|
setSelectedConversationIds(new Set());
|
|
1405
1413
|
setConversationMessagesById({});
|
|
@@ -1423,12 +1431,13 @@ function InboxContent({ userUid }) {
|
|
|
1423
1431
|
return rest.length === 0 ? [first] : [first, ...(await moveMessages(rest, first.folderUid))];
|
|
1424
1432
|
}
|
|
1425
1433
|
/**
|
|
1426
|
-
* This mailbox's folder of `type
|
|
1427
|
-
*
|
|
1428
|
-
*
|
|
1434
|
+
* This mailbox's folder of `type`. The server makes every well-known folder itself (when the mailbox is made, and again when the folders are listed
|
|
1435
|
+
* if one is missing), so a folder the page's tree lacks is asked for - the tree may simply be out of date - and used, never created a second time: a
|
|
1436
|
+
* duplicate of a well-known type is invisible to the server (it answers with the oldest) but would be a second row in the sidebar. Only a server that
|
|
1437
|
+
* really has none (an older one, which makes Deleted Items and Junk on first use) is asked to create it.
|
|
1429
1438
|
*
|
|
1430
|
-
* A folder created here
|
|
1431
|
-
*
|
|
1439
|
+
* A folder found or created here may not be in `mailboxFolders` yet, so it is filed there and remembered per mailbox and type until the page
|
|
1440
|
+
* reloads; otherwise a second Delete would ask again.
|
|
1432
1441
|
*/
|
|
1433
1442
|
async function resolveFolderOfType(type, name) {
|
|
1434
1443
|
const key = `${activeMailboxUid}:${type}`;
|
|
@@ -1436,6 +1445,12 @@ function InboxContent({ userUid }) {
|
|
|
1436
1445
|
if (known) {
|
|
1437
1446
|
return known;
|
|
1438
1447
|
}
|
|
1448
|
+
const listed = (await listFolders(activeMailboxUid)).find((f) => f.type === type);
|
|
1449
|
+
if (listed) {
|
|
1450
|
+
onFolderCreated(listed);
|
|
1451
|
+
lazyFoldersRef.current.set(key, listed.uid);
|
|
1452
|
+
return listed.uid;
|
|
1453
|
+
}
|
|
1439
1454
|
const created = await createFolder({ mailboxUid: activeMailboxUid, name, type });
|
|
1440
1455
|
lazyFoldersRef.current.set(key, created.uid);
|
|
1441
1456
|
return created.uid;
|
|
@@ -1570,7 +1585,7 @@ function InboxContent({ userUid }) {
|
|
|
1570
1585
|
chosen = selectMode ? selectedMessages : inConversations ? await loadOpenConversation(openThread.conversation) : [selected];
|
|
1571
1586
|
}
|
|
1572
1587
|
catch (err) {
|
|
1573
|
-
|
|
1588
|
+
notifyApiError(err, "Couldn't load the messages in that conversation");
|
|
1574
1589
|
return;
|
|
1575
1590
|
}
|
|
1576
1591
|
chosen = chosen.filter(applies);
|
|
@@ -1637,7 +1652,7 @@ function InboxContent({ userUid }) {
|
|
|
1637
1652
|
// Optimistic: the rows and the folder badges change now, and change back if the server refuses.
|
|
1638
1653
|
(chosen) => setReadStateMany(chosen, read, { patch: patchListedMessage, track: trackMessageChange }), false), onSetFlagged: (flagged) => void runBulkAction((chosen) => setMessagesFlagged(chosen, flagged), false), shortcuts: keyboardActions, onArchive: () => void runBulkAction(bulkArchive, true), onMoveTo: async (targetFolderUid) => {
|
|
1639
1654
|
await runBulkAction((chosen) => moveMessages(chosen, targetFolderUid), true);
|
|
1640
|
-
}, onReportJunk: () => void moveSelectionToType("junk", "Junk Email"), onDelete: () => void moveSelectionToType("deleted_items", "Deleted Items"), busy: bulkBusy || resolvingSelection > 0
|
|
1655
|
+
}, onReportJunk: () => void moveSelectionToType("junk", "Junk Email"), onDelete: () => void moveSelectionToType("deleted_items", "Deleted Items"), busy: bulkBusy || resolvingSelection > 0 })) : (_jsx(MailListToolbar, { sortBy: preferences.sortBy, sortOrder: preferences.sortOrder, filter: preferences.filter, labelUids: preferences.labelUids, labels: mailboxLabels, mailboxUid: activeMailboxUid, onLabelCreated: (label) => setMailboxLabels((prev) => [...prev, label]), onLabelUidsChange: (nextLabelUids) => updatePreferences({ labelUids: nextLabelUids }), showAsConversations: preferences.showAsConversations, onSortChange: (sortBy, sortOrder) => updatePreferences({ sortBy, sortOrder }), onFilterChange: (filter) => updatePreferences({ filter }), onShowAsConversationsChange: (showAsConversations) => updatePreferences({ showAsConversations }), selectMode: selectMode, onSelectModeChange: setSelectMode, offerClassificationFilters: offerClassificationFilters, filterDisabled: isSearching, filterDisabledReason: "Filters don't apply to search results", sortKeysDisabled: isSearching || !!aggregateFolderType,
|
|
1641
1656
|
// A conversation row is a thread summary, so only some of the keys have anything to
|
|
1642
1657
|
// order by - the rest stay pickable and are applied to the rows already fetched.
|
|
1643
1658
|
unavailableSortKeys: preferences.showAsConversations ? CONVERSATION_SORT_UNAVAILABLE : undefined, sortKeysNote: isSearching
|
|
@@ -1659,11 +1674,14 @@ function InboxContent({ userUid }) {
|
|
|
1659
1674
|
? `${messages.length} result${messages.length === 1 ? "" : "s"}`
|
|
1660
1675
|
: `${messages.length} of ??` }), tier2Done && !searchAllMail && (_jsx("button", { type: "button", onClick: handleSearchAllMail, className: "text-primary-dark hover:underline font-medium shrink-0", children: "Search all mail" }))] })), isSearching && coverage?.indexedFrom && (_jsxs("div", { className: "px-4 py-1.5 text-xs text-text-muted border-b border-border", children: ["Local search covers messages back to ", new Date(coverage.indexedFrom).toLocaleDateString(), coverage.building ? " (still building)" : "", searchAllMail
|
|
1661
1676
|
? " - searching everything, not just recent mail."
|
|
1662
|
-
: " - older encrypted mail is still searched, just slower."] })), isSearching && !getUnlockedKeys(mailboxUid) && (_jsx("div", { className: "px-4 py-2 border-b border-border bg-surface-alt", children: _jsxs("button", { type: "button", onClick: handleUnlockSearch, className: "inline-flex items-center gap-1 text-xs font-medium text-primary-dark hover:underline", children: [_jsx(HiOutlineLockClosed, { size: 12, "aria-hidden": "true" }), "Unlock to include encrypted messages in these results"] }) })), !isSearching && !preferences.showAsConversations && undecryptedEncryptedUids.length > 0 && !getUnlockedKeys(activeMailboxUid) && (_jsx("div", { className: "px-4 py-2 border-b border-border bg-surface-alt", children: _jsxs("button", { type: "button", onClick: handleUnlockList, className: "inline-flex items-center gap-1 text-xs font-medium text-primary-dark hover:underline", children: [_jsx(HiOutlineLockClosed, { size: 12, "aria-hidden": "true" }), "Unlock to show ", undecryptedEncryptedUids.length === 1 ? "an encrypted message's" : "encrypted messages'", " subject"] }) })), error && (_jsx("div", { className: "p-4", children: _jsx(Alert, { children: error }) })),
|
|
1677
|
+
: " - older encrypted mail is still searched, just slower."] })), isSearching && !getUnlockedKeys(mailboxUid) && (_jsx("div", { className: "px-4 py-2 border-b border-border bg-surface-alt", children: _jsxs("button", { type: "button", onClick: handleUnlockSearch, className: "inline-flex items-center gap-1 text-xs font-medium text-primary-dark hover:underline", children: [_jsx(HiOutlineLockClosed, { size: 12, "aria-hidden": "true" }), "Unlock to include encrypted messages in these results"] }) })), !isSearching && !preferences.showAsConversations && undecryptedEncryptedUids.length > 0 && !getUnlockedKeys(activeMailboxUid) && (_jsx("div", { className: "px-4 py-2 border-b border-border bg-surface-alt", children: _jsxs("button", { type: "button", onClick: handleUnlockList, className: "inline-flex items-center gap-1 text-xs font-medium text-primary-dark hover:underline", children: [_jsx(HiOutlineLockClosed, { size: 12, "aria-hidden": "true" }), "Unlock to show ", undecryptedEncryptedUids.length === 1 ? "an encrypted message's" : "encrypted messages'", " subject"] }) })), error && (_jsx("div", { className: "p-4", children: _jsx(Alert, { children: error }) })), loading ? (_jsxs("div", { role: "status", "aria-busy": "true", className: "p-4", children: [_jsx("span", { className: "sr-only", children: "Loading\u2026" }), _jsx(SkeletonList, { count: 8 })] })) : preferences.showAsConversations ? (_jsxs(_Fragment, { children: [_jsx(ConversationList, { conversations: listedConversations, newestFirst: preferences.sortBy === "date" && preferences.sortOrder === "desc", mailboxUid: activeMailboxUid, selectedUid: selectedUid, messageOverrides: conversationPatches, onOpenMessage: handleOpenConversation, selectMode: selectMode, selectedConversationIds: selectedConversationIds, onToggleSelected: toggleConversationSelected }), hasMore && (_jsx("div", { ref: setSentinel, "data-testid": "load-more-sentinel", className: "p-4 text-center text-xs text-text-muted", children: loadMoreStatus }))] })) : messages.length === 0 ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "p-4 text-sm text-text-muted", children: isSearching
|
|
1663
1678
|
? `No messages match "${searchQuery}".`
|
|
1664
1679
|
: effectiveFilter === "all"
|
|
1665
1680
|
? "No messages in this folder."
|
|
1666
|
-
: "No messages here." }), hasMore && (_jsx("div", { ref: setSentinel, "data-testid": "load-more-sentinel", className: "p-4 text-center text-xs text-text-muted", children: loadMoreStatus }))] })) : (_jsxs(_Fragment, { children: [_jsx("ul", { children: messages.map((message) => (_jsxs("li", { "data-message-uid": message.uid, "data-unread": isUnread(message) ? "true" : undefined, className: rowClass({ unread: isUnread(message), selected: message.uid === selectedUid || selectedUids.has(message.uid) }, "flex items-stretch"), children: [_jsx(UnreadBar, { unread: isUnread(message) }), selectMode && (_jsx("span", { className: "shrink-0 flex items-center pl-3", children: _jsx("input", { type: "checkbox", checked: selectedUids.has(message.uid), onChange: () => toggleSelected(message.uid), "aria-label": `Select ${rowSubject(message)}`, className: "w-4 h-4 accent-primary" }) })), _jsxs("button", { type: "button", "data-row-open": true, onClick: () => handleSelect(message), className: ["flex-1 min-w-0 text-left px-4 py-3", ROW_FOCUS_CLASS].join(" "), children: [_jsx(UnreadLabel, { unread: isUnread(message) }), _jsxs("div", { className: "flex items-center justify-between gap-2 text-sm", children: [_jsx(MailAddress, { recipient: message.from, className: senderClass(isUnread(message)) }), _jsx("span", { className: ["text-xs shrink-0", dateClass(isUnread(message))].join(" "), children: new Date(message.receivedDate).toLocaleDateString() })] }), aggregateFolderType && (_jsx("div", { className: "text-xs text-text-muted truncate font-normal", children: mailboxes.find((mb) => mb.uid === message.mailboxUid)?.displayName })), isSearching && pendingUids.has(message.uid) ? (_jsxs("div", { className: "flex flex-col gap-1.5 py-0.5", children: [_jsx(Skeleton, { height: "h-3.5", className: "w-2/3 rounded-sm" }), _jsx(Skeleton, { height: "h-3", className: "w-full rounded-sm" })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: ["text-sm truncate", subjectClass(isUnread(message))].join(" "), children: rowSubject(message) }), _jsxs("div", { className: "flex items-center gap-2 text-xs text-text-muted font-normal", children: [_jsx("span", { className: "truncate", children: snippets[message.uid] ||
|
|
1681
|
+
: "No messages here." }), hasMore && (_jsx("div", { ref: setSentinel, "data-testid": "load-more-sentinel", className: "p-4 text-center text-xs text-text-muted", children: loadMoreStatus }))] })) : (_jsxs(_Fragment, { children: [_jsx("ul", { children: messages.map((message) => (_jsxs("li", { "data-message-uid": message.uid, "data-unread": isUnread(message) ? "true" : undefined, className: rowClass({ unread: isUnread(message), selected: message.uid === selectedUid || selectedUids.has(message.uid) }, "flex items-stretch"), children: [_jsx(UnreadBar, { unread: isUnread(message) }), selectMode && (_jsx("span", { className: "shrink-0 flex items-center pl-3", children: _jsx("input", { type: "checkbox", checked: selectedUids.has(message.uid), onChange: () => toggleSelected(message.uid), "aria-label": `Select ${rowSubject(message)}`, className: "w-4 h-4 accent-primary" }) })), _jsxs("button", { type: "button", "data-row-open": true, onClick: () => handleSelect(message), className: ["flex-1 min-w-0 text-left px-4 py-3", ROW_FOCUS_CLASS].join(" "), children: [_jsx(UnreadLabel, { unread: isUnread(message) }), _jsxs("div", { className: "flex items-center justify-between gap-2 text-sm", children: [_jsx(MailAddress, { recipient: message.from, className: senderClass(isUnread(message)) }), _jsx("span", { className: ["text-xs shrink-0", dateClass(isUnread(message))].join(" "), children: new Date(message.receivedDate).toLocaleDateString() })] }), aggregateFolderType && (_jsx("div", { className: "text-xs text-text-muted truncate font-normal", children: mailboxes.find((mb) => mb.uid === message.mailboxUid)?.displayName })), isSearching && pendingUids.has(message.uid) ? (_jsxs("div", { className: "flex flex-col gap-1.5 py-0.5", children: [_jsx(Skeleton, { height: "h-3.5", className: "w-2/3 rounded-sm" }), _jsx(Skeleton, { height: "h-3", className: "w-full rounded-sm" })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: ["text-sm truncate", subjectClass(isUnread(message))].join(" "), children: rowSubject(message) }), _jsxs("div", { className: "flex items-center gap-2 text-xs text-text-muted font-normal", children: [_jsx("span", { className: "truncate", children: snippets[message.uid] ||
|
|
1682
|
+
decryptedRows[message.uid]?.preview ||
|
|
1683
|
+
message.bodyPreview ||
|
|
1684
|
+
(message.encrypted ? _jsx(EncryptedPreview, {}) : null) }), message.hasAttachments && _jsx(HiOutlinePaperClip, { size: 12, "aria-label": "Has attachments" }), message.flags.flagged && (_jsx(HiOutlineFlag, { size: 12, "aria-label": "Flagged", className: "text-danger" }))] }), isOutbox && _jsx(OutboxRowStatus, { message: message })] }))] })] }, message.uid))) }), hasMore && (_jsx("div", { ref: setSentinel, "data-testid": "load-more-sentinel", className: "p-4 text-center text-xs text-text-muted", children: loadMoreStatus })), aggregateFolderType && (_jsx("p", { className: "p-4 text-center text-xs text-text-muted", children: "Showing the most recent mail from each mailbox. Open a specific mailbox\u2019s folder to see older mail." }))] }))] }), _jsx("div", { className: "hidden md:flex flex-1 min-w-0 min-h-0", children: preferences.showAsConversations ? (_jsx(LazyConversationThreadPane, { conversation: openThread?.conversation ?? null, selectedUid: openThread?.uid ?? null, mailboxUid: activeMailboxUid, folders: currentFolders, labels: mailboxLabels, shortcuts: !selectMode, onMessagePatched: patchListedMessage, onMessageRemoved: (updated) => removeListedMessage(updated.uid), onLabelCreated: (label) => setMailboxLabels((prev) => [...prev, label]), onFolderCreated: onFolderCreated })) : (_jsx(LazyMessageDetailPane, { shortcuts: !selectMode, message: selected, attachments: attachments, isSentItems: isSentItems, onRecalled: patchListedMessage, isOutbox: isOutbox, onReceiptHandled: patchListedMessage, draftsFolderUid: draftsFolderUid, folders: folders, onMoved: (updated) => {
|
|
1667
1685
|
// Same reasoning as onArchived below - a move takes the message out of the folder
|
|
1668
1686
|
// being listed, so it leaves the list rather than being patched in place.
|
|
1669
1687
|
removeListedMessage(updated.uid);
|
|
@@ -12,6 +12,7 @@ import { useMessageAttachments } from "@rapidmx/react-shared/mail/mailDetailHook
|
|
|
12
12
|
import { useMarkMessageRead } from "../../shared/mail/useMarkMessageRead.js";
|
|
13
13
|
import MailShell, { useMailShell } from "../../shared/components/mail/layout/MailShell.js";
|
|
14
14
|
import { LazyMessageDetailPane } from "../../shared/components/mail/LazyReadingPane.js";
|
|
15
|
+
import { ReadingPaneSkeleton } from "../../shared/components/mail/reading/MessageCard.js";
|
|
15
16
|
import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
|
|
16
17
|
/**
|
|
17
18
|
* Only reached on mobile (below the `md` breakpoint) — desktop's `apps/www/index.tsx` keeps its existing
|
|
@@ -57,7 +58,8 @@ function MessageDetailContent({ uid }) {
|
|
|
57
58
|
const attachments = useMessageAttachments(message);
|
|
58
59
|
useMarkMessageRead(message, setMessage);
|
|
59
60
|
if (loading) {
|
|
60
|
-
|
|
61
|
+
// The pane's own frame - a header card and a message card - rather than a line of text: what is coming is known, only not yet its contents.
|
|
62
|
+
return _jsx(ReadingPaneSkeleton, {});
|
|
61
63
|
}
|
|
62
64
|
if (error || !message) {
|
|
63
65
|
return _jsx(Alert, { children: error ?? "Message not found." });
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { SettingsShellProps } from "../../../shared/components/settings/layout/SettingsShell.js";
|
|
2
|
+
export type SettingsAppearancePageProps = Omit<SettingsShellProps, "active">;
|
|
3
|
+
declare const _default: import("../../../shared/navigation/AppRouter.js").RoutedPageComponent<SettingsAppearancePageProps>;
|
|
4
|
+
export default _default;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
3
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
4
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
5
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
6
|
+
import { routedPage } from "../../_routedPage.js";
|
|
7
|
+
import SettingsShell from "../../../shared/components/settings/layout/SettingsShell.js";
|
|
8
|
+
import AppearanceForm from "../../../shared/appearance/AppearanceForm.js";
|
|
9
|
+
/** Settings > Appearance: the colour scheme, theme colours and background. Not mailbox-scoped - it is the signed-in user's own. */
|
|
10
|
+
function SettingsAppearancePage(props) {
|
|
11
|
+
return (_jsx(SettingsShell, { ...props, active: "appearance", children: _jsx(AppearanceForm, {}) }));
|
|
12
|
+
}
|
|
13
|
+
export default routedPage("/settings/appearance", SettingsAppearancePage);
|
|
@@ -5,12 +5,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
5
5
|
///////////////////////////////////////////////////////////////////////////////
|
|
6
6
|
import { routedPage } from "../../_routedPage.js";
|
|
7
7
|
import { useState } from "react";
|
|
8
|
-
import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
|
|
9
8
|
import { toDatetimeLocal } from "@rapidmx/react-shared/util/dateInput.js";
|
|
10
9
|
import { updateMailbox } from "@rapidmx/react-shared/mail/mailApi.js";
|
|
11
10
|
import SettingsShell, { useSettingsShell } from "../../../shared/components/settings/layout/SettingsShell.js";
|
|
12
|
-
import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
|
|
13
11
|
import Button from "@rapidmx/react-shared/components/buttons/Button.js";
|
|
12
|
+
import { notifyApiError } from "../../../shared/notifications/apiErrors.js";
|
|
14
13
|
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";
|
|
15
14
|
function SettingsAutoReplyPage(props) {
|
|
16
15
|
return (_jsx(SettingsShell, { ...props, active: "auto-reply", children: _jsx(AutoReplyContent, {}) }));
|
|
@@ -28,12 +27,10 @@ function AutoReplyContent() {
|
|
|
28
27
|
// `SettingsShell`'s `mailboxes` is fetched once - every save bumps the server's version, so a second
|
|
29
28
|
// save without a reload must send the version the previous save returned, not the stale original.
|
|
30
29
|
const [version, setVersion] = useState(mailbox.version);
|
|
31
|
-
const [error, setError] = useState(null);
|
|
32
30
|
const [saving, setSaving] = useState(false);
|
|
33
31
|
const [saved, setSaved] = useState(false);
|
|
34
32
|
async function handleSubmit(e) {
|
|
35
33
|
e.preventDefault();
|
|
36
|
-
setError(null);
|
|
37
34
|
setSaved(false);
|
|
38
35
|
setSaving(true);
|
|
39
36
|
try {
|
|
@@ -50,12 +47,12 @@ function AutoReplyContent() {
|
|
|
50
47
|
setSaved(true);
|
|
51
48
|
}
|
|
52
49
|
catch (err) {
|
|
53
|
-
|
|
50
|
+
notifyApiError(err, "Couldn't save the automatic reply settings");
|
|
54
51
|
}
|
|
55
52
|
finally {
|
|
56
53
|
setSaving(false);
|
|
57
54
|
}
|
|
58
55
|
}
|
|
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."] }),
|
|
56
|
+
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."] }), saved && _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" }) })] })] }) }));
|
|
60
57
|
}
|
|
61
58
|
export default routedPage("/settings/auto-reply", SettingsAutoReplyPage);
|