@rapidmx/web-client 0.20.0 → 0.21.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 (118) hide show
  1. package/README.md +381 -381
  2. package/apps/admin/branding/index.tsx +39 -39
  3. package/apps/admin/data-requests/index.tsx +482 -482
  4. package/apps/admin/domains/[uid].tsx +166 -166
  5. package/apps/admin/escrow-scopes/[uid].tsx +350 -350
  6. package/apps/admin/index.tsx +129 -129
  7. package/apps/admin/mailboxes/[uid].tsx +271 -271
  8. package/apps/admin/mailboxes/new/index.tsx +30 -30
  9. package/apps/admin/plugins/index.tsx +15 -15
  10. package/apps/admin/retention-policy/index.tsx +39 -39
  11. package/apps/admin/signing-certificates/index.tsx +343 -343
  12. package/apps/escrow/audit-log/index.tsx +196 -196
  13. package/apps/escrow/matters/[uid].tsx +621 -621
  14. package/apps/shared/auth/adminAccess.ts +99 -99
  15. package/apps/shared/components/admin/layout/AdminShell.tsx +384 -384
  16. package/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.tsx +238 -238
  17. package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -152
  18. package/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.tsx +194 -194
  19. package/apps/shared/components/admin/settings/BrandingForm.tsx +423 -423
  20. package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +119 -119
  21. package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +198 -198
  22. package/apps/shared/components/admin/settings/PluginsManager.tsx +2093 -2093
  23. package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +182 -182
  24. package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +288 -288
  25. package/apps/shared/components/admin/setup/SetupWizard.tsx +446 -446
  26. package/apps/shared/components/admin/usePagedList.tsx +129 -129
  27. package/apps/shared/components/calendar/EventModal.tsx +206 -206
  28. package/apps/shared/components/calendar/MonthView.tsx +185 -185
  29. package/apps/shared/components/calendar/RecurrenceEditor.tsx +227 -227
  30. package/apps/shared/components/calendar/SplitDayView.tsx +144 -144
  31. package/apps/shared/components/calendar/TimeGridView.tsx +246 -246
  32. package/apps/shared/components/calendar/allDay.ts +124 -124
  33. package/apps/shared/components/contacts/ContactForm.tsx +383 -383
  34. package/apps/shared/components/contacts/ContactsToolbar.tsx +103 -103
  35. package/apps/shared/components/escrow/layout/EscrowShell.tsx +155 -155
  36. package/apps/shared/components/layout/AppShell.tsx +463 -461
  37. package/apps/shared/components/layout/KeyEnrollmentGate.tsx +398 -398
  38. package/apps/shared/components/layout/MailboxProvisioning.tsx +168 -168
  39. package/apps/shared/components/layout/ResponsiveToolbar.tsx +315 -315
  40. package/apps/shared/components/layout/ThemeSwitch.tsx +84 -84
  41. package/apps/shared/components/layout/UserMenu.tsx +439 -439
  42. package/apps/shared/components/mail/ConversationList.tsx +332 -332
  43. package/apps/shared/components/mail/ConversationThreadPane.tsx +613 -613
  44. package/apps/shared/components/mail/MailSelectionBar.tsx +240 -240
  45. package/apps/shared/components/mail/MenuButton.tsx +404 -404
  46. package/apps/shared/components/mail/MessageDetailPane.tsx +1757 -1757
  47. package/apps/shared/components/mail/compose/ComposeContext.tsx +312 -312
  48. package/apps/shared/components/mail/compose/ComposeToolbar.tsx +422 -422
  49. package/apps/shared/components/mail/compose/ComposeWindow.tsx +1705 -1681
  50. package/apps/shared/components/mail/compose/RichTextEditor.tsx +147 -147
  51. package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -60
  52. package/apps/shared/components/mail/compose/quotedBody.ts +161 -161
  53. package/apps/shared/components/mail/reading/MessageMoreMenu.tsx +258 -258
  54. package/apps/shared/components/mail/reading/MessageSourceDialog.tsx +79 -79
  55. package/apps/shared/components/mail/reading/messageExport.ts +59 -59
  56. package/apps/shared/components/mail/reading/printMessage.ts +99 -99
  57. package/apps/shared/components/mail/reading/useMessageActions.ts +443 -443
  58. package/apps/shared/components/mail/verificationSeals.ts +125 -125
  59. package/apps/shared/components/rules/RuleBuilder.tsx +311 -311
  60. package/apps/shared/components/settings/SigningCertificateCard.tsx +344 -344
  61. package/apps/shared/keyboard/GlobalShortcuts.tsx +51 -51
  62. package/apps/shared/keyboard/ShortcutProvider.tsx +62 -62
  63. package/apps/shared/keyboard/ShortcutsDialog.tsx +84 -84
  64. package/apps/shared/keyboard/dispatch.ts +124 -124
  65. package/apps/shared/keyboard/format.ts +89 -89
  66. package/apps/shared/keyboard/keymap.ts +114 -114
  67. package/apps/shared/keyboard/registry.ts +65 -65
  68. package/apps/shared/keyboard/targets.ts +79 -79
  69. package/apps/shared/mail/folderOfType.ts +49 -49
  70. package/apps/shared/mail/folderTree.ts +143 -143
  71. package/apps/shared/mail/listAllPages.ts +39 -39
  72. package/apps/shared/mail/newMailNotifications.ts +171 -171
  73. package/apps/shared/mail/outbox/sendJob.ts +445 -445
  74. package/apps/shared/mail/outbox/sendOutcomes.ts +155 -155
  75. package/apps/shared/mail/reportNotices.ts +66 -66
  76. package/apps/shared/mail/senderBlocking.ts +141 -141
  77. package/apps/shared/mail/useMailConnection.ts +205 -205
  78. package/apps/shared/mail/useMailLiveUpdates.ts +277 -277
  79. package/apps/shared/mail/useMailboxUpdateAccess.ts +60 -60
  80. package/apps/shared/mail/useMarkMessageRead.ts +47 -47
  81. package/apps/shared/mail/useNewMailNotifications.ts +178 -178
  82. package/apps/shared/notifications/store.ts +560 -560
  83. package/apps/shared/search/LocalIndexLifecycle.tsx +114 -114
  84. package/apps/shared/search/localIndexBuilder.ts +481 -481
  85. package/apps/shared/signing/enrollmentStorage.ts +33 -33
  86. package/apps/shared/signing/enrollmentTracker.ts +385 -385
  87. package/apps/shared/signing/enrollmentView.ts +251 -251
  88. package/apps/shared/signing/useNow.ts +19 -19
  89. package/apps/shared/signing/useSigningEnrollmentWatcher.ts +90 -90
  90. package/apps/shared/styles/app.css +396 -396
  91. package/apps/www/calendar/index.tsx +581 -581
  92. package/apps/www/contacts/[uid].tsx +112 -112
  93. package/apps/www/index.tsx +3012 -3012
  94. package/apps/www/messages/[uid].tsx +139 -139
  95. package/apps/www/settings/auto-reply/index.tsx +136 -136
  96. package/apps/www/settings/blocked-senders/index.tsx +303 -303
  97. package/apps/www/settings/encryption/index.tsx +1290 -1290
  98. package/apps/www/settings/filters/[uid].tsx +179 -179
  99. package/apps/www/settings/filters/index.tsx +105 -105
  100. package/apps/www/settings/filters/new/index.tsx +165 -165
  101. package/apps/www/settings/labels/index.tsx +207 -207
  102. package/apps/www/settings/privacy/index.tsx +495 -495
  103. package/apps/www/settings/profile/index.tsx +251 -251
  104. package/apps/www/settings/read-receipts/index.tsx +150 -150
  105. package/apps/www/settings/sharing/index.tsx +259 -259
  106. package/apps/www/settings/signatures/[uid].tsx +175 -175
  107. package/apps/www/settings/signatures/index.tsx +91 -91
  108. package/apps/www/settings/signatures/new/index.tsx +138 -138
  109. package/apps/www/tasks/index.tsx +654 -654
  110. package/dist/apps/shared/components/admin/layout/AdminShell.js +2 -2
  111. package/dist/apps/shared/components/admin/settings/BrandingForm.js +3 -3
  112. package/dist/apps/shared/components/escrow/layout/EscrowShell.js +2 -2
  113. package/dist/apps/shared/components/layout/AppShell.js +4 -2
  114. package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +7 -1
  115. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +20 -1
  116. package/dist/apps/shared/components/mail/reading/printMessage.js +11 -11
  117. package/dist/apps/shared/styles/app.css +396 -396
  118. package/package.json +2 -2
@@ -1,124 +1,124 @@
1
- ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2026 Jean-Philippe Steinmetz
3
- // SPDX-License-Identifier: MPL-2.0
4
- ///////////////////////////////////////////////////////////////////////////////
5
- import { format } from "date-fns";
6
- import { WeekdayCode } from "@rapidmx/react-shared/calendar/calendarApi.js";
7
- import { CalendarOccurrence, toEventWallClock } from "@rapidmx/react-shared/calendar/recurrence.js";
8
-
9
- const MS_PER_DAY = 86_400_000;
10
-
11
- /**
12
- * All-day events are stored date-only: `startDate` is UTC midnight of the first day and `endDate` is UTC
13
- * midnight of the day *after* the last day (exclusive, like iCalendar's `DTEND;VALUE=DATE`). That keeps
14
- * an all-day event on the same calendar date for every viewer, whatever their timezone.
15
- *
16
- * Older events were saved as the creator's *local* midnight converted to UTC (e.g. `...T22:00Z` for a
17
- * UTC+2 creator), so reading one rounds the instant to the nearest UTC midnight rather than slicing the
18
- * ISO string — which gives the intended date for both formats.
19
- */
20
- export function allDayDateKey(iso: string): string {
21
- const rounded = Math.round(new Date(iso).getTime() / MS_PER_DAY) * MS_PER_DAY;
22
- return new Date(rounded).toISOString().slice(0, 10);
23
- }
24
-
25
- /** `YYYY-MM-DD` -> the stored UTC-midnight instant for that date. */
26
- export function allDayInstant(dateKey: string): string {
27
- return `${dateKey}T00:00:00.000Z`;
28
- }
29
-
30
- /** Adds `days` to a `YYYY-MM-DD` date key. */
31
- export function addDaysToKey(dateKey: string, days: number): string {
32
- return new Date(new Date(allDayInstant(dateKey)).getTime() + days * MS_PER_DAY).toISOString().slice(0, 10);
33
- }
34
-
35
- /** The local calendar date `day` (a local-midnight `Date` from a grid view) as a `YYYY-MM-DD` key. */
36
- export function localDateKey(day: Date): string {
37
- return format(day, "yyyy-MM-dd");
38
- }
39
-
40
- /**
41
- * A recurrence rule's inclusive "Ends on" date -> its stored `until` instant: the end of that day in the
42
- * frame the series expands in. A timed series expands in its own (normally the viewer's) timezone, so that's
43
- * the end of the local day - `new Date("YYYY-MM-DD")` would be UTC midnight, the previous day west of UTC.
44
- * An all-day series expands in UTC (react-shared's `expandOccurrences`), so it's the end of the UTC day: the
45
- * local end of day is already the next UTC day west of UTC and would add one more occurrence.
46
- */
47
- export function recurrenceUntilInstant(dateKey: string, allDay: boolean): string {
48
- if (allDay) {
49
- return `${dateKey}T23:59:59.999Z`;
50
- }
51
- const [y, m, d] = dateKey.split("-").map(Number);
52
- return new Date(y, m - 1, d, 23, 59, 59, 999).toISOString();
53
- }
54
-
55
- /** The stored form of an all-day series' "Ends on" date - the last millisecond of that UTC day. */
56
- const ALL_DAY_UNTIL_PATTERN = /^(\d{4}-\d{2}-\d{2})T23:59:59\.999Z$/;
57
- /** A bare UTC midnight - how the oldest editor (and date-only `UNTIL` values) stored the chosen date itself. */
58
- const UTC_MIDNIGHT_PATTERN = /^(\d{4}-\d{2}-\d{2})T00:00:00(?:\.000)?Z$/;
59
-
60
- /**
61
- * Inverse of `recurrenceUntilInstant()`. An all-day series' value is recognized explicitly in its stored
62
- * `T23:59:59.999Z` form (and as a bare UTC midnight, the oldest form). Anything else is a legacy value stored
63
- * as the creator's *local* end of day, which can land anywhere from just before 10:00Z on the chosen date (UTC+14)
64
- * to just before 12:00Z the day after (UTC-12) - a 26-hour spread no UTC-only rounding can resolve (UTC+14 and UTC-10
65
- * creators' values are exactly 24h apart for the same date), so it reads back on the local calendar, the
66
- * frame it was written in.
67
- */
68
- export function recurrenceUntilDateKey(until: string, allDay: boolean): string {
69
- if (allDay) {
70
- const stored = ALL_DAY_UNTIL_PATTERN.exec(until) ?? UTC_MIDNIGHT_PATTERN.exec(until);
71
- if (stored) {
72
- return stored[1];
73
- }
74
- }
75
- return format(new Date(until), "yyyy-MM-dd");
76
- }
77
-
78
- /** `Date#getUTCDay()` index -> RFC 5545 weekday code. */
79
- const JS_WEEKDAY_CODES: WeekdayCode[] = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"];
80
-
81
- /** The weekday an event starts on, in the frame its series expands in: the UTC date for an all-day event
82
- * (`start`'s date part), the event's own timezone otherwise (`start` being a local `datetime-local` value).
83
- * `undefined` while the start input is empty/invalid. */
84
- export function startWeekdayCode(start: string, allDay: boolean, timezone: string | undefined): WeekdayCode | undefined {
85
- const ms = allDay ? new Date(allDayInstant(start.slice(0, 10))).getTime() : new Date(start).getTime();
86
- if (Number.isNaN(ms)) {
87
- return undefined;
88
- }
89
- return JS_WEEKDAY_CODES[new Date(toEventWallClock(ms, timezone, allDay)).getUTCDay()];
90
- }
91
-
92
- /**
93
- * Whether `occurrence` should be shown on the grid's local calendar day `day`. All-day events cover every
94
- * date from their start date up to (not including) their exclusive end date — at least their start date.
95
- * Timed events cover every local day their [start, end) interval overlaps, so a multi-day event shows on
96
- * each day rather than only on its start day.
97
- */
98
- export function occursOnDay(occurrence: CalendarOccurrence, day: Date): boolean {
99
- if (occurrence.allDay) {
100
- const key = localDateKey(day);
101
- const startKey = allDayDateKey(occurrence.startDate);
102
- const endKey = allDayDateKey(occurrence.endDate);
103
- return key === startKey || (key > startKey && key < endKey);
104
- }
105
- const dayStart = new Date(day.getFullYear(), day.getMonth(), day.getDate());
106
- const dayEnd = new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1);
107
- const start = new Date(occurrence.startDate);
108
- const end = new Date(occurrence.endDate);
109
- if (start.getTime() === end.getTime()) {
110
- return start >= dayStart && start < dayEnd;
111
- }
112
- return start < dayEnd && end > dayStart;
113
- }
114
-
115
- /**
116
- * Whether `day` is the first day `occurrence` covers. Grid views only make that day's chip/block
117
- * draggable — a drag id must be unique, so the continuation copies on later days are display-only.
118
- */
119
- export function startsOnDay(occurrence: CalendarOccurrence, day: Date): boolean {
120
- if (occurrence.allDay) {
121
- return allDayDateKey(occurrence.startDate) === localDateKey(day);
122
- }
123
- return localDateKey(new Date(occurrence.startDate)) === localDateKey(day);
124
- }
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import { format } from "date-fns";
6
+ import { WeekdayCode } from "@rapidmx/react-shared/calendar/calendarApi.js";
7
+ import { CalendarOccurrence, toEventWallClock } from "@rapidmx/react-shared/calendar/recurrence.js";
8
+
9
+ const MS_PER_DAY = 86_400_000;
10
+
11
+ /**
12
+ * All-day events are stored date-only: `startDate` is UTC midnight of the first day and `endDate` is UTC
13
+ * midnight of the day *after* the last day (exclusive, like iCalendar's `DTEND;VALUE=DATE`). That keeps
14
+ * an all-day event on the same calendar date for every viewer, whatever their timezone.
15
+ *
16
+ * Older events were saved as the creator's *local* midnight converted to UTC (e.g. `...T22:00Z` for a
17
+ * UTC+2 creator), so reading one rounds the instant to the nearest UTC midnight rather than slicing the
18
+ * ISO string — which gives the intended date for both formats.
19
+ */
20
+ export function allDayDateKey(iso: string): string {
21
+ const rounded = Math.round(new Date(iso).getTime() / MS_PER_DAY) * MS_PER_DAY;
22
+ return new Date(rounded).toISOString().slice(0, 10);
23
+ }
24
+
25
+ /** `YYYY-MM-DD` -> the stored UTC-midnight instant for that date. */
26
+ export function allDayInstant(dateKey: string): string {
27
+ return `${dateKey}T00:00:00.000Z`;
28
+ }
29
+
30
+ /** Adds `days` to a `YYYY-MM-DD` date key. */
31
+ export function addDaysToKey(dateKey: string, days: number): string {
32
+ return new Date(new Date(allDayInstant(dateKey)).getTime() + days * MS_PER_DAY).toISOString().slice(0, 10);
33
+ }
34
+
35
+ /** The local calendar date `day` (a local-midnight `Date` from a grid view) as a `YYYY-MM-DD` key. */
36
+ export function localDateKey(day: Date): string {
37
+ return format(day, "yyyy-MM-dd");
38
+ }
39
+
40
+ /**
41
+ * A recurrence rule's inclusive "Ends on" date -> its stored `until` instant: the end of that day in the
42
+ * frame the series expands in. A timed series expands in its own (normally the viewer's) timezone, so that's
43
+ * the end of the local day - `new Date("YYYY-MM-DD")` would be UTC midnight, the previous day west of UTC.
44
+ * An all-day series expands in UTC (react-shared's `expandOccurrences`), so it's the end of the UTC day: the
45
+ * local end of day is already the next UTC day west of UTC and would add one more occurrence.
46
+ */
47
+ export function recurrenceUntilInstant(dateKey: string, allDay: boolean): string {
48
+ if (allDay) {
49
+ return `${dateKey}T23:59:59.999Z`;
50
+ }
51
+ const [y, m, d] = dateKey.split("-").map(Number);
52
+ return new Date(y, m - 1, d, 23, 59, 59, 999).toISOString();
53
+ }
54
+
55
+ /** The stored form of an all-day series' "Ends on" date - the last millisecond of that UTC day. */
56
+ const ALL_DAY_UNTIL_PATTERN = /^(\d{4}-\d{2}-\d{2})T23:59:59\.999Z$/;
57
+ /** A bare UTC midnight - how the oldest editor (and date-only `UNTIL` values) stored the chosen date itself. */
58
+ const UTC_MIDNIGHT_PATTERN = /^(\d{4}-\d{2}-\d{2})T00:00:00(?:\.000)?Z$/;
59
+
60
+ /**
61
+ * Inverse of `recurrenceUntilInstant()`. An all-day series' value is recognized explicitly in its stored
62
+ * `T23:59:59.999Z` form (and as a bare UTC midnight, the oldest form). Anything else is a legacy value stored
63
+ * as the creator's *local* end of day, which can land anywhere from just before 10:00Z on the chosen date (UTC+14)
64
+ * to just before 12:00Z the day after (UTC-12) - a 26-hour spread no UTC-only rounding can resolve (UTC+14 and UTC-10
65
+ * creators' values are exactly 24h apart for the same date), so it reads back on the local calendar, the
66
+ * frame it was written in.
67
+ */
68
+ export function recurrenceUntilDateKey(until: string, allDay: boolean): string {
69
+ if (allDay) {
70
+ const stored = ALL_DAY_UNTIL_PATTERN.exec(until) ?? UTC_MIDNIGHT_PATTERN.exec(until);
71
+ if (stored) {
72
+ return stored[1];
73
+ }
74
+ }
75
+ return format(new Date(until), "yyyy-MM-dd");
76
+ }
77
+
78
+ /** `Date#getUTCDay()` index -> RFC 5545 weekday code. */
79
+ const JS_WEEKDAY_CODES: WeekdayCode[] = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"];
80
+
81
+ /** The weekday an event starts on, in the frame its series expands in: the UTC date for an all-day event
82
+ * (`start`'s date part), the event's own timezone otherwise (`start` being a local `datetime-local` value).
83
+ * `undefined` while the start input is empty/invalid. */
84
+ export function startWeekdayCode(start: string, allDay: boolean, timezone: string | undefined): WeekdayCode | undefined {
85
+ const ms = allDay ? new Date(allDayInstant(start.slice(0, 10))).getTime() : new Date(start).getTime();
86
+ if (Number.isNaN(ms)) {
87
+ return undefined;
88
+ }
89
+ return JS_WEEKDAY_CODES[new Date(toEventWallClock(ms, timezone, allDay)).getUTCDay()];
90
+ }
91
+
92
+ /**
93
+ * Whether `occurrence` should be shown on the grid's local calendar day `day`. All-day events cover every
94
+ * date from their start date up to (not including) their exclusive end date — at least their start date.
95
+ * Timed events cover every local day their [start, end) interval overlaps, so a multi-day event shows on
96
+ * each day rather than only on its start day.
97
+ */
98
+ export function occursOnDay(occurrence: CalendarOccurrence, day: Date): boolean {
99
+ if (occurrence.allDay) {
100
+ const key = localDateKey(day);
101
+ const startKey = allDayDateKey(occurrence.startDate);
102
+ const endKey = allDayDateKey(occurrence.endDate);
103
+ return key === startKey || (key > startKey && key < endKey);
104
+ }
105
+ const dayStart = new Date(day.getFullYear(), day.getMonth(), day.getDate());
106
+ const dayEnd = new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1);
107
+ const start = new Date(occurrence.startDate);
108
+ const end = new Date(occurrence.endDate);
109
+ if (start.getTime() === end.getTime()) {
110
+ return start >= dayStart && start < dayEnd;
111
+ }
112
+ return start < dayEnd && end > dayStart;
113
+ }
114
+
115
+ /**
116
+ * Whether `day` is the first day `occurrence` covers. Grid views only make that day's chip/block
117
+ * draggable — a drag id must be unique, so the continuation copies on later days are display-only.
118
+ */
119
+ export function startsOnDay(occurrence: CalendarOccurrence, day: Date): boolean {
120
+ if (occurrence.allDay) {
121
+ return allDayDateKey(occurrence.startDate) === localDateKey(day);
122
+ }
123
+ return localDateKey(new Date(occurrence.startDate)) === localDateKey(day);
124
+ }