@rapidmx/web-client 0.3.1 → 0.5.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/apps/admin/audit-log/index.tsx +35 -8
- package/apps/admin/branding/index.tsx +39 -404
- package/apps/admin/data-requests/index.tsx +480 -485
- package/apps/admin/distribution-lists/[uid].tsx +19 -1
- package/apps/admin/domains/[uid].tsx +92 -259
- package/apps/admin/encryption-policy/index.tsx +19 -0
- package/apps/admin/escrow-scopes/[uid].tsx +348 -237
- package/apps/admin/escrow-scopes/new/index.tsx +8 -2
- package/apps/admin/index.tsx +118 -82
- package/apps/admin/ingest-queue/index.tsx +44 -5
- package/apps/admin/mailbox-policy/index.tsx +19 -0
- package/apps/admin/mailboxes/[uid].tsx +211 -184
- package/apps/admin/mailboxes/new/index.tsx +28 -291
- package/apps/admin/plugins/index.tsx +15 -0
- package/apps/admin/quarantine/index.tsx +46 -14
- package/apps/admin/retention-policy/index.tsx +39 -132
- package/apps/admin/setup/index.tsx +15 -0
- package/apps/admin/transport-rules/[uid].tsx +30 -1
- package/apps/admin/transport-rules/_transportRuleConfig.tsx +38 -2
- package/apps/admin/transport-rules/index.tsx +24 -6
- package/apps/admin/transport-rules/new/index.tsx +30 -1
- package/apps/escrow/_layout.tsx +2 -3
- package/apps/escrow/audit-log/index.tsx +196 -168
- package/apps/escrow/matters/[uid].tsx +621 -521
- package/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.tsx +22 -1
- package/apps/shared/components/admin/layout/AdminShell.tsx +251 -210
- package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -0
- package/apps/shared/components/admin/mailboxes/ResourceSettingsCard.tsx +3 -3
- package/apps/shared/components/admin/mailboxes/ShareAccessCard.tsx +55 -11
- package/apps/shared/components/admin/settings/BrandingForm.tsx +385 -0
- package/apps/shared/components/admin/settings/DomainDnsSetup.tsx +187 -0
- package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +112 -0
- package/apps/shared/components/admin/settings/LoadedSettingsForm.tsx +34 -0
- package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +308 -0
- package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +152 -0
- package/apps/shared/components/admin/settings/PluginsManager.tsx +1235 -0
- package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +174 -0
- package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +290 -0
- package/apps/shared/components/admin/setup/SetupWizard.tsx +416 -0
- package/apps/shared/components/admin/signOut.ts +79 -0
- package/apps/shared/components/admin/usePagedList.tsx +129 -0
- package/apps/shared/components/calendar/CalendarListSidebar.tsx +120 -76
- package/apps/shared/components/calendar/EventModal.tsx +717 -513
- package/apps/shared/components/calendar/MonthView.tsx +173 -139
- package/apps/shared/components/calendar/RecurrenceEditor.tsx +222 -180
- package/apps/shared/components/calendar/SplitDayView.tsx +143 -137
- package/apps/shared/components/calendar/TimeGridView.tsx +244 -198
- package/apps/shared/components/calendar/allDay.ts +124 -0
- package/apps/shared/components/calendar/layout/CalendarShell.tsx +80 -99
- package/apps/shared/components/contacts/ContactDetailPane.tsx +100 -21
- package/apps/shared/components/contacts/ContactForm.tsx +377 -314
- package/apps/shared/components/contacts/ContactsSidebar.tsx +6 -2
- package/apps/shared/components/contacts/KeyChangeReview.tsx +192 -0
- package/apps/shared/components/contacts/contactKeys.ts +78 -0
- package/apps/shared/components/escrow/layout/EscrowShell.tsx +148 -134
- package/apps/shared/components/layout/AppShell.tsx +270 -169
- package/apps/shared/components/layout/BrandingChrome.tsx +48 -10
- package/apps/shared/components/layout/KeyEnrollmentGate.tsx +150 -26
- package/apps/shared/components/layout/MailboxProvisioning.tsx +19 -3
- package/apps/shared/components/layout/RecoveryCodeUnlock.tsx +350 -0
- package/apps/shared/components/layout/UnlockPromptProvider.tsx +257 -0
- package/apps/shared/components/mail/ConversationThreadPane.tsx +216 -181
- package/apps/shared/components/mail/MessageDetailPane.tsx +799 -76
- package/apps/shared/components/mail/compose/ComposeContext.tsx +26 -16
- package/apps/shared/components/mail/compose/ComposeWindow.tsx +1652 -765
- package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -0
- package/apps/shared/components/mail/layout/MailShell.tsx +418 -302
- package/apps/shared/components/mail/pinnedSigners.ts +124 -0
- package/apps/shared/components/mail/verificationSeals.ts +125 -0
- package/apps/shared/components/mail/writableMailboxes.ts +101 -0
- package/apps/shared/components/rules/RuleBuilder.tsx +311 -276
- package/apps/shared/components/settings/layout/SettingsShell.tsx +1 -0
- package/apps/shared/mail/findWellKnownFolderUid.ts +13 -0
- package/apps/shared/mail/listAllPages.ts +39 -0
- package/apps/shared/search/LocalIndexLifecycle.tsx +98 -0
- package/apps/shared/search/localIndexBlockCipher.ts +83 -0
- package/apps/shared/search/localIndexBuilder.ts +481 -0
- package/apps/shared/search/localIndexKey.ts +27 -0
- package/apps/shared/search/localIndexRpcClient.ts +316 -0
- package/apps/shared/search/localIndexSchema.ts +236 -0
- package/apps/shared/search/localIndexSizePreference.ts +88 -0
- package/apps/shared/search/localIndexStorage.ts +98 -0
- package/apps/shared/search/localIndexVFS.ts +266 -0
- package/apps/shared/search/localIndexWorker.ts +926 -0
- package/apps/shared/search/searchTier2.ts +79 -0
- package/apps/shared/search/wa-sqlite-shims.d.ts +44 -0
- package/apps/www/calendar/index.tsx +438 -407
- package/apps/www/contacts/[uid].tsx +21 -2
- package/apps/www/contacts/index.tsx +148 -17
- package/apps/www/index.tsx +1314 -486
- package/apps/www/messages/[uid].tsx +23 -7
- package/apps/www/settings/auto-reply/index.tsx +134 -129
- package/apps/www/settings/booking-types/[uid].tsx +306 -300
- package/apps/www/settings/encryption/index.tsx +800 -215
- package/apps/www/settings/filters/[uid].tsx +171 -155
- package/apps/www/settings/filters/new/index.tsx +8 -1
- package/apps/www/settings/focused-inbox/index.tsx +150 -148
- package/apps/www/settings/privacy/index.tsx +494 -436
- package/apps/www/settings/read-receipts/index.tsx +148 -125
- package/apps/www/settings/sharing/index.tsx +274 -0
- package/apps/www/tasks/index.tsx +638 -530
- package/dist/apps/admin/audit-log/index.js +38 -8
- package/dist/apps/admin/branding/index.js +4 -98
- package/dist/apps/admin/data-requests/index.js +52 -72
- package/dist/apps/admin/distribution-lists/[uid].js +1 -1
- package/dist/apps/admin/domains/[uid].js +5 -68
- package/dist/apps/admin/encryption-policy/index.js +8 -0
- package/dist/apps/admin/escrow-scopes/[uid].js +91 -12
- package/dist/apps/admin/escrow-scopes/new/index.js +8 -3
- package/dist/apps/admin/index.js +17 -1
- package/dist/apps/admin/ingest-queue/index.js +24 -6
- package/dist/apps/admin/mailbox-policy/index.js +8 -0
- package/dist/apps/admin/mailboxes/[uid].js +20 -4
- package/dist/apps/admin/mailboxes/new/index.js +4 -89
- package/dist/apps/admin/plugins/index.js +6 -0
- package/dist/apps/admin/quarantine/index.js +20 -11
- package/dist/apps/admin/retention-policy/index.js +3 -36
- package/dist/apps/admin/setup/index.js +6 -0
- package/dist/apps/admin/transport-rules/[uid].js +18 -2
- package/dist/apps/admin/transport-rules/_transportRuleConfig.js +19 -0
- package/dist/apps/admin/transport-rules/index.js +22 -6
- package/dist/apps/admin/transport-rules/new/index.js +18 -2
- package/dist/apps/escrow/_layout.js +3 -3
- package/dist/apps/escrow/audit-log/index.js +26 -1
- package/dist/apps/escrow/matters/[uid].js +77 -42
- package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js +11 -2
- package/dist/apps/shared/components/admin/layout/AdminShell.js +37 -4
- package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.js +72 -0
- package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.js +3 -3
- package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +22 -4
- package/dist/apps/shared/components/admin/settings/BrandingForm.js +116 -0
- package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +83 -0
- package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +62 -0
- package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.js +25 -0
- package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +112 -0
- package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +74 -0
- package/dist/apps/shared/components/admin/settings/PluginsManager.js +572 -0
- package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +73 -0
- package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +147 -0
- package/dist/apps/shared/components/admin/setup/SetupWizard.js +208 -0
- package/dist/apps/shared/components/admin/signOut.js +75 -0
- package/dist/apps/shared/components/admin/usePagedList.js +99 -0
- package/dist/apps/shared/components/calendar/CalendarListSidebar.js +24 -13
- package/dist/apps/shared/components/calendar/EventModal.js +154 -21
- package/dist/apps/shared/components/calendar/MonthView.js +12 -5
- package/dist/apps/shared/components/calendar/RecurrenceEditor.js +40 -5
- package/dist/apps/shared/components/calendar/SplitDayView.js +10 -4
- package/dist/apps/shared/components/calendar/TimeGridView.js +23 -7
- package/dist/apps/shared/components/calendar/allDay.js +111 -0
- package/dist/apps/shared/components/calendar/layout/CalendarShell.js +47 -39
- package/dist/apps/shared/components/contacts/ContactDetailPane.js +43 -5
- package/dist/apps/shared/components/contacts/ContactForm.js +45 -12
- package/dist/apps/shared/components/contacts/ContactsSidebar.js +2 -2
- package/dist/apps/shared/components/contacts/KeyChangeReview.js +63 -0
- package/dist/apps/shared/components/contacts/contactKeys.js +64 -0
- package/dist/apps/shared/components/escrow/layout/EscrowShell.js +24 -5
- package/dist/apps/shared/components/layout/AppShell.js +100 -8
- package/dist/apps/shared/components/layout/BrandingChrome.js +45 -10
- package/dist/apps/shared/components/layout/KeyEnrollmentGate.js +63 -14
- package/dist/apps/shared/components/layout/MailboxProvisioning.js +10 -2
- package/dist/apps/shared/components/layout/RecoveryCodeUnlock.js +174 -0
- package/dist/apps/shared/components/layout/UnlockPromptProvider.js +136 -0
- package/dist/apps/shared/components/mail/ConversationThreadPane.js +50 -12
- package/dist/apps/shared/components/mail/MessageDetailPane.js +464 -34
- package/dist/apps/shared/components/mail/compose/ComposeContext.js +9 -6
- package/dist/apps/shared/components/mail/compose/ComposeWindow.js +807 -116
- package/dist/apps/shared/components/mail/compose/composeFlushRegistry.js +50 -0
- package/dist/apps/shared/components/mail/layout/MailShell.js +116 -41
- package/dist/apps/shared/components/mail/pinnedSigners.js +98 -0
- package/dist/apps/shared/components/mail/verificationSeals.js +112 -0
- package/dist/apps/shared/components/mail/writableMailboxes.js +87 -0
- package/dist/apps/shared/components/rules/RuleBuilder.js +34 -6
- package/dist/apps/shared/components/settings/layout/SettingsShell.js +1 -0
- package/dist/apps/shared/mail/findWellKnownFolderUid.js +12 -0
- package/dist/apps/shared/mail/listAllPages.js +25 -0
- package/dist/apps/shared/search/LocalIndexLifecycle.js +80 -0
- package/dist/apps/shared/search/localIndexBlockCipher.js +63 -0
- package/dist/apps/shared/search/localIndexBuilder.js +408 -0
- package/dist/apps/shared/search/localIndexKey.js +25 -0
- package/dist/apps/shared/search/localIndexRpcClient.js +241 -0
- package/dist/apps/shared/search/localIndexSchema.js +185 -0
- package/dist/apps/shared/search/localIndexSizePreference.js +78 -0
- package/dist/apps/shared/search/localIndexStorage.js +86 -0
- package/dist/apps/shared/search/localIndexVFS.js +258 -0
- package/dist/apps/shared/search/localIndexWorker.js +687 -0
- package/dist/apps/shared/search/searchTier2.js +38 -0
- package/dist/apps/www/calendar/index.js +38 -18
- package/dist/apps/www/contacts/[uid].js +13 -2
- package/dist/apps/www/contacts/index.js +94 -15
- package/dist/apps/www/index.js +770 -137
- package/dist/apps/www/messages/[uid].js +23 -7
- package/dist/apps/www/settings/auto-reply/index.js +9 -4
- package/dist/apps/www/settings/booking-types/[uid].js +17 -12
- package/dist/apps/www/settings/encryption/index.js +541 -96
- package/dist/apps/www/settings/filters/[uid].js +22 -7
- package/dist/apps/www/settings/filters/new/index.js +8 -2
- package/dist/apps/www/settings/focused-inbox/index.js +3 -1
- package/dist/apps/www/settings/privacy/index.js +57 -22
- package/dist/apps/www/settings/read-receipts/index.js +10 -3
- package/dist/apps/www/settings/sharing/index.js +124 -0
- package/dist/apps/www/tasks/index.js +76 -14
- package/package.json +3 -2
|
@@ -58,7 +58,25 @@ function DistributionListDetailContent({ uid }: { uid: string }) {
|
|
|
58
58
|
<dt className="text-text-muted">Alias addresses</dt>
|
|
59
59
|
<dd>{list.aliasAddresses && list.aliasAddresses.length > 0 ? list.aliasAddresses.join(", ") : "None"}</dd>
|
|
60
60
|
<dt className="text-text-muted">Restrict senders</dt>
|
|
61
|
-
<dd>
|
|
61
|
+
<dd>
|
|
62
|
+
{list.restrictSenders ? "Only members may send" : "No"}
|
|
63
|
+
{/* restapi accepts a member's message only when the mail server's own trusted Authentication-Results
|
|
64
|
+
(`mail:security:trusted_authserv_id`) report a passing, aligned DKIM signature. That setting is
|
|
65
|
+
empty by default and no API reports it, so this is static text rather than a conditional warning. */}
|
|
66
|
+
{list.restrictSenders ? (
|
|
67
|
+
<p role="status" className="mt-1.5 py-2 px-3 rounded-sm text-xs bg-warning/15 text-text">
|
|
68
|
+
Members are recognized only by a verified (DKIM) signature, which requires the mail server’s
|
|
69
|
+
Authentication-Results configuration (the trusted authserv id,{" "}
|
|
70
|
+
<code>mail:security:trusted_authserv_id</code>). If that isn’t configured, all mail sent to
|
|
71
|
+
this list is dropped.
|
|
72
|
+
</p>
|
|
73
|
+
) : (
|
|
74
|
+
<p className="mt-1 text-xs text-text-muted">
|
|
75
|
+
Restricting senders to members requires the mail server’s Authentication-Results configuration
|
|
76
|
+
(the trusted authserv id); without it, all mail to the list is dropped.
|
|
77
|
+
</p>
|
|
78
|
+
)}
|
|
79
|
+
</dd>
|
|
62
80
|
<dt className="text-text-muted">Created</dt>
|
|
63
81
|
<dd>{new Date(list.dateCreated).toLocaleString()}</dd>
|
|
64
82
|
</dl>
|
|
@@ -1,259 +1,92 @@
|
|
|
1
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
-
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
-
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
-
import React, {
|
|
6
|
-
import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
|
|
7
|
-
import { deleteDomain,
|
|
8
|
-
import AdminShell, { AdminShellProps } from "../../shared/components/admin/layout/AdminShell.js";
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
async function handleCopy(value: string) {
|
|
94
|
-
try {
|
|
95
|
-
await navigator.clipboard.writeText(value);
|
|
96
|
-
setCopied(true);
|
|
97
|
-
setTimeout(() => setCopied(false), 2000);
|
|
98
|
-
} catch {
|
|
99
|
-
// Clipboard access can be denied by the browser — the value is still selectable/copyable by hand.
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (loading) {
|
|
104
|
-
return <p className="text-sm text-text-muted">Loading…</p>;
|
|
105
|
-
}
|
|
106
|
-
if (error || !domain) {
|
|
107
|
-
return <Alert>{error ?? "Domain not found."}</Alert>;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const ownershipCheck = dnsSetup.find((c) => c.type === "ownership");
|
|
111
|
-
|
|
112
|
-
return (
|
|
113
|
-
<div className="max-w-3xl flex flex-col gap-5">
|
|
114
|
-
<div className="flex items-start justify-between gap-4">
|
|
115
|
-
<div>
|
|
116
|
-
<a href="/admin/domains" className="text-sm text-primary-dark hover:underline">
|
|
117
|
-
← All domains
|
|
118
|
-
</a>
|
|
119
|
-
<h1 className="text-xl font-bold tracking-tight mt-1">{domain.name}</h1>
|
|
120
|
-
</div>
|
|
121
|
-
<Button
|
|
122
|
-
type="button"
|
|
123
|
-
variant="secondary"
|
|
124
|
-
className="!w-auto shrink-0 !border-danger !text-danger hover:!border-danger hover:!text-danger"
|
|
125
|
-
onClick={() => setConfirmingDelete(true)}
|
|
126
|
-
>
|
|
127
|
-
Delete domain
|
|
128
|
-
</Button>
|
|
129
|
-
</div>
|
|
130
|
-
|
|
131
|
-
<div className="bg-surface border border-border rounded-md p-6">
|
|
132
|
-
<dl className="grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-3 text-sm">
|
|
133
|
-
<dt className="text-text-muted">Enabled</dt>
|
|
134
|
-
<dd>{domain.enabled ? "Yes" : "No"}</dd>
|
|
135
|
-
<dt className="text-text-muted">Verification</dt>
|
|
136
|
-
<dd>
|
|
137
|
-
{domain.verified ? (
|
|
138
|
-
<span className="text-xs font-bold uppercase tracking-wide py-0.5 px-2 rounded-pill bg-success text-white">
|
|
139
|
-
Verified
|
|
140
|
-
</span>
|
|
141
|
-
) : (
|
|
142
|
-
<span className="text-xs font-bold uppercase tracking-wide py-0.5 px-2 rounded-pill bg-surface-alt text-text-muted">
|
|
143
|
-
Unverified
|
|
144
|
-
</span>
|
|
145
|
-
)}
|
|
146
|
-
</dd>
|
|
147
|
-
<dt className="text-text-muted">Last checked</dt>
|
|
148
|
-
<dd>{domain.lastCheckedAt ? new Date(domain.lastCheckedAt).toLocaleString() : "Never"}</dd>
|
|
149
|
-
</dl>
|
|
150
|
-
|
|
151
|
-
{!domain.verified && (
|
|
152
|
-
<div className="mt-5 pt-5 border-t border-border">
|
|
153
|
-
<p className="text-sm mb-2">
|
|
154
|
-
Add the following TXT record to <strong>{domain.name}</strong> to prove ownership, then verify:
|
|
155
|
-
</p>
|
|
156
|
-
<div className="flex items-center gap-2">
|
|
157
|
-
<code className="flex-1 text-xs bg-surface-alt border border-border rounded-sm py-2 px-3 overflow-x-auto whitespace-nowrap">
|
|
158
|
-
{ownershipCheck?.recommendedValue ?? `rapidmx-domain-verification=${domain.verificationToken}`}
|
|
159
|
-
</code>
|
|
160
|
-
<Button
|
|
161
|
-
type="button"
|
|
162
|
-
variant="secondary"
|
|
163
|
-
className="!w-auto shrink-0"
|
|
164
|
-
onClick={() =>
|
|
165
|
-
handleCopy(
|
|
166
|
-
ownershipCheck?.recommendedValue ?? `rapidmx-domain-verification=${domain.verificationToken}`,
|
|
167
|
-
)
|
|
168
|
-
}
|
|
169
|
-
>
|
|
170
|
-
{copied ? "Copied" : "Copy"}
|
|
171
|
-
</Button>
|
|
172
|
-
</div>
|
|
173
|
-
<Button
|
|
174
|
-
type="button"
|
|
175
|
-
className="!w-auto mt-3"
|
|
176
|
-
loading={verifying}
|
|
177
|
-
disabled={verifying}
|
|
178
|
-
onClick={handleVerify}
|
|
179
|
-
>
|
|
180
|
-
Verify now
|
|
181
|
-
</Button>
|
|
182
|
-
</div>
|
|
183
|
-
)}
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
{dnsSetup.length > 0 && (
|
|
187
|
-
<div className="bg-surface border border-border rounded-md p-6">
|
|
188
|
-
<h2 className="text-sm font-bold uppercase tracking-wide mb-3">DNS setup checklist</h2>
|
|
189
|
-
<div className="overflow-x-auto">
|
|
190
|
-
<table className="w-full text-sm border-collapse">
|
|
191
|
-
<thead>
|
|
192
|
-
<tr>
|
|
193
|
-
{["Record", "Status", "Recommended value"].map((h) => (
|
|
194
|
-
<th
|
|
195
|
-
key={h}
|
|
196
|
-
className="text-left text-xs uppercase tracking-wide text-text-muted py-2 px-2.5 border-b border-border"
|
|
197
|
-
>
|
|
198
|
-
{h}
|
|
199
|
-
</th>
|
|
200
|
-
))}
|
|
201
|
-
</tr>
|
|
202
|
-
</thead>
|
|
203
|
-
<tbody>
|
|
204
|
-
{dnsSetup.map((check) => (
|
|
205
|
-
<tr key={check.type}>
|
|
206
|
-
<td className="py-2.5 px-2.5 border-b border-border">{RECORD_TYPE_LABELS[check.type]}</td>
|
|
207
|
-
<td className="py-2.5 px-2.5 border-b border-border">
|
|
208
|
-
{!check.configured ? (
|
|
209
|
-
<span className="text-xs text-text-muted">Not configured</span>
|
|
210
|
-
) : check.matches ? (
|
|
211
|
-
<span className="text-xs font-bold uppercase tracking-wide py-0.5 px-2 rounded-pill bg-success text-white">
|
|
212
|
-
Live
|
|
213
|
-
</span>
|
|
214
|
-
) : (
|
|
215
|
-
<span className="text-xs font-bold uppercase tracking-wide py-0.5 px-2 rounded-pill bg-surface-alt text-text-muted">
|
|
216
|
-
Not found
|
|
217
|
-
</span>
|
|
218
|
-
)}
|
|
219
|
-
</td>
|
|
220
|
-
<td className="py-2.5 px-2.5 border-b border-border text-text-muted">
|
|
221
|
-
<code className="text-xs">{check.recommendedValue ?? "—"}</code>
|
|
222
|
-
</td>
|
|
223
|
-
</tr>
|
|
224
|
-
))}
|
|
225
|
-
</tbody>
|
|
226
|
-
</table>
|
|
227
|
-
</div>
|
|
228
|
-
</div>
|
|
229
|
-
)}
|
|
230
|
-
|
|
231
|
-
<Modal open={confirmingDelete} onClose={closeDeleteModal} title="Delete domain">
|
|
232
|
-
<p className="text-sm mb-5">
|
|
233
|
-
Are you sure you want to delete <strong>{domain.name}</strong>? This cannot be undone.
|
|
234
|
-
</p>
|
|
235
|
-
{deleteError && <Alert>{deleteError}</Alert>}
|
|
236
|
-
<div className="flex gap-3 justify-end mt-5">
|
|
237
|
-
<Button
|
|
238
|
-
type="button"
|
|
239
|
-
variant="secondary"
|
|
240
|
-
className="!w-auto"
|
|
241
|
-
disabled={deleting}
|
|
242
|
-
onClick={closeDeleteModal}
|
|
243
|
-
>
|
|
244
|
-
Cancel
|
|
245
|
-
</Button>
|
|
246
|
-
<Button
|
|
247
|
-
type="button"
|
|
248
|
-
className="!w-auto !bg-none !bg-danger !border-danger hover:!bg-danger"
|
|
249
|
-
loading={deleting}
|
|
250
|
-
disabled={deleting}
|
|
251
|
-
onClick={handleDelete}
|
|
252
|
-
>
|
|
253
|
-
Delete
|
|
254
|
-
</Button>
|
|
255
|
-
</div>
|
|
256
|
-
</Modal>
|
|
257
|
-
</div>
|
|
258
|
-
);
|
|
259
|
-
}
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import React, { useState } from "react";
|
|
6
|
+
import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
|
|
7
|
+
import { deleteDomain, Domain } from "@rapidmx/react-shared/admin/domainsApi.js";
|
|
8
|
+
import AdminShell, { AdminShellProps } from "../../shared/components/admin/layout/AdminShell.js";
|
|
9
|
+
import DomainDnsSetup from "../../shared/components/admin/settings/DomainDnsSetup.js";
|
|
10
|
+
import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
|
|
11
|
+
import Button from "@rapidmx/react-shared/components/buttons/Button.js";
|
|
12
|
+
import Modal from "@rapidmx/react-shared/components/overlays/Modal.js";
|
|
13
|
+
|
|
14
|
+
export default function DomainDetailPage(props: Omit<AdminShellProps, "active"> & { params: { uid: string } }) {
|
|
15
|
+
return (
|
|
16
|
+
<AdminShell {...props} active="domains">
|
|
17
|
+
<DomainDetailContent uid={props.params.uid} />
|
|
18
|
+
</AdminShell>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function DomainDetailContent({ uid }: { uid: string }) {
|
|
23
|
+
const [domain, setDomain] = useState<Domain | null>(null);
|
|
24
|
+
const [confirmingDelete, setConfirmingDelete] = useState(false);
|
|
25
|
+
const [deleting, setDeleting] = useState(false);
|
|
26
|
+
const [deleteError, setDeleteError] = useState<string | null>(null);
|
|
27
|
+
|
|
28
|
+
function closeDeleteModal() {
|
|
29
|
+
setConfirmingDelete(false);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Only ever invoked from the "Delete domain" confirmation modal, which only renders once `domain` is loaded.
|
|
33
|
+
async function handleDelete() {
|
|
34
|
+
setDeleting(true);
|
|
35
|
+
setDeleteError(null);
|
|
36
|
+
try {
|
|
37
|
+
await deleteDomain(domain!.uid, domain!.version);
|
|
38
|
+
window.location.href = "/admin/domains";
|
|
39
|
+
} catch (err) {
|
|
40
|
+
setDeleteError(err instanceof ApiRequestError ? err.message : "Could not delete this domain.");
|
|
41
|
+
setDeleting(false);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div className="max-w-3xl flex flex-col gap-5">
|
|
47
|
+
{domain && (
|
|
48
|
+
<div className="flex items-start justify-between gap-4">
|
|
49
|
+
<div>
|
|
50
|
+
<a href="/admin/domains" className="text-sm text-primary-dark hover:underline">
|
|
51
|
+
← All domains
|
|
52
|
+
</a>
|
|
53
|
+
<h1 className="text-xl font-bold tracking-tight mt-1">{domain.name}</h1>
|
|
54
|
+
</div>
|
|
55
|
+
<Button
|
|
56
|
+
type="button"
|
|
57
|
+
variant="secondary"
|
|
58
|
+
className="!w-auto shrink-0 !border-danger !text-danger hover:!border-danger hover:!text-danger"
|
|
59
|
+
onClick={() => setConfirmingDelete(true)}
|
|
60
|
+
>
|
|
61
|
+
Delete domain
|
|
62
|
+
</Button>
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
65
|
+
|
|
66
|
+
<DomainDnsSetup uid={uid} onLoaded={setDomain} />
|
|
67
|
+
|
|
68
|
+
{domain && (
|
|
69
|
+
<Modal open={confirmingDelete} onClose={closeDeleteModal} title="Delete domain">
|
|
70
|
+
<p className="text-sm mb-5">
|
|
71
|
+
Are you sure you want to delete <strong>{domain.name}</strong>? This cannot be undone.
|
|
72
|
+
</p>
|
|
73
|
+
{deleteError && <Alert>{deleteError}</Alert>}
|
|
74
|
+
<div className="flex gap-3 justify-end mt-5">
|
|
75
|
+
<Button type="button" variant="secondary" className="!w-auto" disabled={deleting} onClick={closeDeleteModal}>
|
|
76
|
+
Cancel
|
|
77
|
+
</Button>
|
|
78
|
+
<Button
|
|
79
|
+
type="button"
|
|
80
|
+
className="!w-auto !bg-none !bg-danger !border-danger hover:!bg-danger"
|
|
81
|
+
loading={deleting}
|
|
82
|
+
disabled={deleting}
|
|
83
|
+
onClick={handleDelete}
|
|
84
|
+
>
|
|
85
|
+
Delete
|
|
86
|
+
</Button>
|
|
87
|
+
</div>
|
|
88
|
+
</Modal>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import React from "react";
|
|
6
|
+
import { getEncryptionPolicy } from "@rapidmx/react-shared/crypto/keyvaultApi.js";
|
|
7
|
+
import AdminShell, { AdminShellProps } from "../../shared/components/admin/layout/AdminShell.js";
|
|
8
|
+
import EncryptionPolicyForm from "../../shared/components/admin/settings/EncryptionPolicyForm.js";
|
|
9
|
+
import LoadedSettingsForm from "../../shared/components/admin/settings/LoadedSettingsForm.js";
|
|
10
|
+
|
|
11
|
+
export default function EncryptionPolicyPage(props: Omit<AdminShellProps, "active">) {
|
|
12
|
+
return (
|
|
13
|
+
<AdminShell {...props} active="encryptionPolicy">
|
|
14
|
+
<LoadedSettingsForm load={getEncryptionPolicy} loadErrorMessage="Could not load the encryption policy.">
|
|
15
|
+
{(policy, onChange) => <EncryptionPolicyForm policy={policy} onChange={onChange} />}
|
|
16
|
+
</LoadedSettingsForm>
|
|
17
|
+
</AdminShell>
|
|
18
|
+
);
|
|
19
|
+
}
|