@rapidmx/web-client 0.19.0 → 0.20.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 +381 -381
- package/apps/admin/branding/index.tsx +39 -39
- package/apps/admin/data-requests/index.tsx +482 -482
- package/apps/admin/domains/[uid].tsx +166 -166
- package/apps/admin/escrow-scopes/[uid].tsx +350 -350
- package/apps/admin/index.tsx +129 -129
- package/apps/admin/mailboxes/[uid].tsx +271 -271
- package/apps/admin/mailboxes/new/index.tsx +30 -30
- package/apps/admin/plugins/index.tsx +15 -15
- package/apps/admin/retention-policy/index.tsx +39 -39
- package/apps/admin/signing-certificates/index.tsx +343 -343
- package/apps/escrow/audit-log/index.tsx +196 -196
- package/apps/escrow/matters/[uid].tsx +621 -621
- package/apps/shared/auth/adminAccess.ts +99 -99
- package/apps/shared/components/admin/diagnostics/HostCard.tsx +2 -0
- package/apps/shared/components/admin/diagnostics/PressureTiles.tsx +108 -0
- package/apps/shared/components/admin/diagnostics/PvcTable.tsx +20 -6
- package/apps/shared/components/admin/diagnostics/diagnosticsApi.ts +21 -2
- package/apps/shared/components/admin/layout/AdminShell.tsx +384 -384
- package/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.tsx +238 -238
- package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -152
- package/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.tsx +194 -194
- package/apps/shared/components/admin/settings/BrandingForm.tsx +423 -423
- package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +119 -119
- package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +198 -198
- package/apps/shared/components/admin/settings/PluginsManager.tsx +2093 -1620
- package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +182 -182
- package/apps/shared/components/admin/settings/pluginPreferences.ts +34 -0
- package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +288 -288
- package/apps/shared/components/admin/setup/SetupWizard.tsx +446 -446
- package/apps/shared/components/admin/usePagedList.tsx +129 -129
- package/apps/shared/components/calendar/EventModal.tsx +206 -206
- package/apps/shared/components/calendar/MonthView.tsx +185 -185
- package/apps/shared/components/calendar/RecurrenceEditor.tsx +227 -227
- package/apps/shared/components/calendar/SplitDayView.tsx +144 -144
- package/apps/shared/components/calendar/TimeGridView.tsx +246 -246
- package/apps/shared/components/calendar/allDay.ts +124 -124
- package/apps/shared/components/contacts/ContactForm.tsx +383 -383
- package/apps/shared/components/contacts/ContactsToolbar.tsx +103 -103
- package/apps/shared/components/escrow/layout/EscrowShell.tsx +155 -155
- package/apps/shared/components/layout/AppShell.tsx +461 -461
- package/apps/shared/components/layout/KeyEnrollmentGate.tsx +398 -398
- package/apps/shared/components/layout/MailboxProvisioning.tsx +168 -168
- package/apps/shared/components/layout/ResponsiveToolbar.tsx +315 -315
- package/apps/shared/components/layout/ThemeSwitch.tsx +84 -84
- package/apps/shared/components/layout/UserMenu.tsx +439 -439
- package/apps/shared/components/mail/ConversationList.tsx +332 -323
- package/apps/shared/components/mail/ConversationThreadPane.tsx +613 -613
- package/apps/shared/components/mail/MailSelectionBar.tsx +240 -240
- package/apps/shared/components/mail/MenuButton.tsx +404 -404
- package/apps/shared/components/mail/MessageDetailPane.tsx +1757 -1757
- package/apps/shared/components/mail/compose/ComposeContext.tsx +312 -312
- package/apps/shared/components/mail/compose/ComposeToolbar.tsx +422 -422
- package/apps/shared/components/mail/compose/ComposeWindow.tsx +1681 -1681
- package/apps/shared/components/mail/compose/RichTextEditor.tsx +147 -147
- package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -60
- package/apps/shared/components/mail/compose/quotedBody.ts +161 -161
- package/apps/shared/components/mail/listPreferences.ts +3 -3
- package/apps/shared/components/mail/reading/MessageMoreMenu.tsx +258 -258
- package/apps/shared/components/mail/reading/MessageSourceDialog.tsx +79 -79
- package/apps/shared/components/mail/reading/messageExport.ts +59 -59
- package/apps/shared/components/mail/reading/printMessage.ts +99 -99
- package/apps/shared/components/mail/reading/useMessageActions.ts +443 -443
- package/apps/shared/components/mail/verificationSeals.ts +125 -125
- package/apps/shared/components/rules/RuleBuilder.tsx +311 -311
- package/apps/shared/components/settings/SigningCertificateCard.tsx +344 -344
- package/apps/shared/keyboard/GlobalShortcuts.tsx +51 -51
- package/apps/shared/keyboard/ShortcutProvider.tsx +62 -62
- package/apps/shared/keyboard/ShortcutsDialog.tsx +84 -84
- package/apps/shared/keyboard/dispatch.ts +124 -124
- package/apps/shared/keyboard/format.ts +89 -89
- package/apps/shared/keyboard/keymap.ts +114 -114
- package/apps/shared/keyboard/registry.ts +65 -65
- package/apps/shared/keyboard/targets.ts +79 -79
- package/apps/shared/mail/folderOfType.ts +49 -49
- package/apps/shared/mail/folderTree.ts +143 -143
- package/apps/shared/mail/listAllPages.ts +39 -39
- package/apps/shared/mail/newMailNotifications.ts +171 -171
- package/apps/shared/mail/outbox/sendJob.ts +445 -445
- package/apps/shared/mail/outbox/sendOutcomes.ts +155 -155
- package/apps/shared/mail/reportNotices.ts +66 -66
- package/apps/shared/mail/senderBlocking.ts +141 -141
- package/apps/shared/mail/useMailConnection.ts +205 -205
- package/apps/shared/mail/useMailLiveUpdates.ts +277 -277
- package/apps/shared/mail/useMailboxUpdateAccess.ts +60 -60
- package/apps/shared/mail/useMarkMessageRead.ts +47 -47
- package/apps/shared/mail/useNewMailNotifications.ts +178 -178
- package/apps/shared/notifications/store.ts +560 -560
- package/apps/shared/search/LocalIndexLifecycle.tsx +114 -114
- package/apps/shared/search/localIndexBuilder.ts +481 -481
- package/apps/shared/signing/enrollmentStorage.ts +33 -33
- package/apps/shared/signing/enrollmentTracker.ts +385 -385
- package/apps/shared/signing/enrollmentView.ts +251 -251
- package/apps/shared/signing/useNow.ts +19 -19
- package/apps/shared/signing/useSigningEnrollmentWatcher.ts +90 -90
- package/apps/shared/styles/app.css +396 -396
- package/apps/www/calendar/index.tsx +581 -581
- package/apps/www/contacts/[uid].tsx +112 -112
- package/apps/www/index.tsx +3012 -2962
- package/apps/www/messages/[uid].tsx +139 -139
- package/apps/www/settings/auto-reply/index.tsx +136 -136
- package/apps/www/settings/blocked-senders/index.tsx +303 -303
- package/apps/www/settings/encryption/index.tsx +1290 -1290
- package/apps/www/settings/filters/[uid].tsx +179 -179
- package/apps/www/settings/filters/index.tsx +105 -105
- package/apps/www/settings/filters/new/index.tsx +165 -165
- package/apps/www/settings/labels/index.tsx +207 -207
- package/apps/www/settings/privacy/index.tsx +495 -495
- package/apps/www/settings/profile/index.tsx +251 -251
- package/apps/www/settings/read-receipts/index.tsx +150 -150
- package/apps/www/settings/sharing/index.tsx +259 -259
- package/apps/www/settings/signatures/[uid].tsx +175 -175
- package/apps/www/settings/signatures/index.tsx +91 -91
- package/apps/www/settings/signatures/new/index.tsx +138 -138
- package/apps/www/tasks/index.tsx +654 -654
- package/dist/apps/shared/components/admin/diagnostics/HostCard.js +2 -1
- package/dist/apps/shared/components/admin/diagnostics/PressureTiles.d.ts +22 -0
- package/dist/apps/shared/components/admin/diagnostics/PressureTiles.js +52 -0
- package/dist/apps/shared/components/admin/diagnostics/PvcTable.js +9 -4
- package/dist/apps/shared/components/admin/diagnostics/diagnosticsApi.d.ts +35 -2
- package/dist/apps/shared/components/admin/settings/BrandingForm.js +3 -3
- package/dist/apps/shared/components/admin/settings/PluginsManager.js +267 -35
- package/dist/apps/shared/components/admin/settings/pluginPreferences.d.ts +2 -0
- package/dist/apps/shared/components/admin/settings/pluginPreferences.js +35 -0
- package/dist/apps/shared/components/mail/ConversationList.d.ts +10 -3
- package/dist/apps/shared/components/mail/ConversationList.js +9 -5
- package/dist/apps/shared/components/mail/listPreferences.d.ts +1 -1
- package/dist/apps/shared/components/mail/reading/printMessage.js +11 -11
- package/dist/apps/shared/styles/app.css +396 -396
- package/dist/apps/www/index.js +51 -10
- package/package.json +2 -2
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
-
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
-
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
-
import React, { useContext, useId, useRef } from "react";
|
|
6
|
-
import { HiOutlineComputerDesktop, HiOutlineMoon, HiOutlineSun } from "react-icons/hi2";
|
|
7
|
-
import type { AppearanceMode } from "@rapidmx/react-shared/appearance/preferencesApi.js";
|
|
8
|
-
import { AppearanceContext, INERT_APPEARANCE } from "../../appearance/appearanceContext.js";
|
|
9
|
-
|
|
10
|
-
const CHOICES: { mode: AppearanceMode; label: string; hint: string; Icon: typeof HiOutlineSun }[] = [
|
|
11
|
-
{ mode: "system", label: "System", hint: "System - follow this device", Icon: HiOutlineComputerDesktop },
|
|
12
|
-
{ mode: "light", label: "Light", hint: "Light", Icon: HiOutlineSun },
|
|
13
|
-
{ mode: "dark", label: "Dark", hint: "Dark", Icon: HiOutlineMoon },
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* The account menu's colour scheme control: a row "Theme" with a three-way segmented control of icon buttons - System, Light, Dark - a
|
|
18
|
-
* `radiogroup` (one tab stop, the arrow keys move and choose, Home/End jump). A choice applies through `useAppearance().setPrefs()`, which
|
|
19
|
-
* changes every open surface in the same frame (the app frame, message cards, the consoles) and saves in the background - and puts the change
|
|
20
|
-
* back, with a notice, if the save fails. Renders nothing where there is no `AppearanceProvider` (a shell that has none, a component tested
|
|
21
|
-
* alone): the hook is inert there and a control that changes nothing would be a lie.
|
|
22
|
-
*/
|
|
23
|
-
export default function ThemeSwitch() {
|
|
24
|
-
const appearance = useContext(AppearanceContext);
|
|
25
|
-
const buttons = useRef<(HTMLButtonElement | null)[]>([]);
|
|
26
|
-
const labelId = useId();
|
|
27
|
-
if (appearance === INERT_APPEARANCE) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
const current = appearance.prefs.mode;
|
|
31
|
-
|
|
32
|
-
function choose(index: number, focus: boolean) {
|
|
33
|
-
const next = CHOICES[(index + CHOICES.length) % CHOICES.length];
|
|
34
|
-
if (next.mode !== current) {
|
|
35
|
-
appearance.setPrefs({ mode: next.mode });
|
|
36
|
-
}
|
|
37
|
-
if (focus) {
|
|
38
|
-
buttons.current[(index + CHOICES.length) % CHOICES.length]?.focus();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function handleKeyDown(event: React.KeyboardEvent, index: number) {
|
|
43
|
-
const target = { ArrowRight: index + 1, ArrowDown: index + 1, ArrowLeft: index - 1, ArrowUp: index - 1, Home: 0, End: CHOICES.length - 1 }[event.key];
|
|
44
|
-
if (target !== undefined) {
|
|
45
|
-
event.preventDefault();
|
|
46
|
-
choose(target, true);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
<div className="flex items-center justify-between gap-3 px-3.5 py-2 border-b border-border">
|
|
52
|
-
<span id={labelId} className="text-sm text-text">
|
|
53
|
-
Theme
|
|
54
|
-
</span>
|
|
55
|
-
<div role="radiogroup" aria-labelledby={labelId} className="inline-flex rounded-sm border border-border bg-surface-alt p-0.5">
|
|
56
|
-
{CHOICES.map(({ mode, label, hint, Icon }, index) => {
|
|
57
|
-
const selected = mode === current;
|
|
58
|
-
return (
|
|
59
|
-
<button
|
|
60
|
-
key={mode}
|
|
61
|
-
ref={(element) => {
|
|
62
|
-
buttons.current[index] = element;
|
|
63
|
-
}}
|
|
64
|
-
type="button"
|
|
65
|
-
role="radio"
|
|
66
|
-
aria-checked={selected}
|
|
67
|
-
aria-label={label}
|
|
68
|
-
title={hint}
|
|
69
|
-
tabIndex={selected ? 0 : -1}
|
|
70
|
-
onClick={() => choose(index, false)}
|
|
71
|
-
onKeyDown={(event) => handleKeyDown(event, index)}
|
|
72
|
-
className={[
|
|
73
|
-
"flex h-7 w-8 items-center justify-center rounded-[3px] focus-visible:outline-2 focus-visible:outline-primary",
|
|
74
|
-
selected ? "bg-surface text-primary-dark shadow-sm" : "text-text-muted hover:text-text",
|
|
75
|
-
].join(" ")}
|
|
76
|
-
>
|
|
77
|
-
<Icon size={16} aria-hidden="true" />
|
|
78
|
-
</button>
|
|
79
|
-
);
|
|
80
|
-
})}
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
);
|
|
84
|
-
}
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import React, { useContext, useId, useRef } from "react";
|
|
6
|
+
import { HiOutlineComputerDesktop, HiOutlineMoon, HiOutlineSun } from "react-icons/hi2";
|
|
7
|
+
import type { AppearanceMode } from "@rapidmx/react-shared/appearance/preferencesApi.js";
|
|
8
|
+
import { AppearanceContext, INERT_APPEARANCE } from "../../appearance/appearanceContext.js";
|
|
9
|
+
|
|
10
|
+
const CHOICES: { mode: AppearanceMode; label: string; hint: string; Icon: typeof HiOutlineSun }[] = [
|
|
11
|
+
{ mode: "system", label: "System", hint: "System - follow this device", Icon: HiOutlineComputerDesktop },
|
|
12
|
+
{ mode: "light", label: "Light", hint: "Light", Icon: HiOutlineSun },
|
|
13
|
+
{ mode: "dark", label: "Dark", hint: "Dark", Icon: HiOutlineMoon },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The account menu's colour scheme control: a row "Theme" with a three-way segmented control of icon buttons - System, Light, Dark - a
|
|
18
|
+
* `radiogroup` (one tab stop, the arrow keys move and choose, Home/End jump). A choice applies through `useAppearance().setPrefs()`, which
|
|
19
|
+
* changes every open surface in the same frame (the app frame, message cards, the consoles) and saves in the background - and puts the change
|
|
20
|
+
* back, with a notice, if the save fails. Renders nothing where there is no `AppearanceProvider` (a shell that has none, a component tested
|
|
21
|
+
* alone): the hook is inert there and a control that changes nothing would be a lie.
|
|
22
|
+
*/
|
|
23
|
+
export default function ThemeSwitch() {
|
|
24
|
+
const appearance = useContext(AppearanceContext);
|
|
25
|
+
const buttons = useRef<(HTMLButtonElement | null)[]>([]);
|
|
26
|
+
const labelId = useId();
|
|
27
|
+
if (appearance === INERT_APPEARANCE) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const current = appearance.prefs.mode;
|
|
31
|
+
|
|
32
|
+
function choose(index: number, focus: boolean) {
|
|
33
|
+
const next = CHOICES[(index + CHOICES.length) % CHOICES.length];
|
|
34
|
+
if (next.mode !== current) {
|
|
35
|
+
appearance.setPrefs({ mode: next.mode });
|
|
36
|
+
}
|
|
37
|
+
if (focus) {
|
|
38
|
+
buttons.current[(index + CHOICES.length) % CHOICES.length]?.focus();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function handleKeyDown(event: React.KeyboardEvent, index: number) {
|
|
43
|
+
const target = { ArrowRight: index + 1, ArrowDown: index + 1, ArrowLeft: index - 1, ArrowUp: index - 1, Home: 0, End: CHOICES.length - 1 }[event.key];
|
|
44
|
+
if (target !== undefined) {
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
choose(target, true);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className="flex items-center justify-between gap-3 px-3.5 py-2 border-b border-border">
|
|
52
|
+
<span id={labelId} className="text-sm text-text">
|
|
53
|
+
Theme
|
|
54
|
+
</span>
|
|
55
|
+
<div role="radiogroup" aria-labelledby={labelId} className="inline-flex rounded-sm border border-border bg-surface-alt p-0.5">
|
|
56
|
+
{CHOICES.map(({ mode, label, hint, Icon }, index) => {
|
|
57
|
+
const selected = mode === current;
|
|
58
|
+
return (
|
|
59
|
+
<button
|
|
60
|
+
key={mode}
|
|
61
|
+
ref={(element) => {
|
|
62
|
+
buttons.current[index] = element;
|
|
63
|
+
}}
|
|
64
|
+
type="button"
|
|
65
|
+
role="radio"
|
|
66
|
+
aria-checked={selected}
|
|
67
|
+
aria-label={label}
|
|
68
|
+
title={hint}
|
|
69
|
+
tabIndex={selected ? 0 : -1}
|
|
70
|
+
onClick={() => choose(index, false)}
|
|
71
|
+
onKeyDown={(event) => handleKeyDown(event, index)}
|
|
72
|
+
className={[
|
|
73
|
+
"flex h-7 w-8 items-center justify-center rounded-[3px] focus-visible:outline-2 focus-visible:outline-primary",
|
|
74
|
+
selected ? "bg-surface text-primary-dark shadow-sm" : "text-text-muted hover:text-text",
|
|
75
|
+
].join(" ")}
|
|
76
|
+
>
|
|
77
|
+
<Icon size={16} aria-hidden="true" />
|
|
78
|
+
</button>
|
|
79
|
+
);
|
|
80
|
+
})}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
}
|