@rapidmx/web-client 0.5.0 → 0.6.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 +88 -0
- package/apps/shared/components/admin/layout/AdminShell.tsx +25 -8
- package/apps/shared/components/calendar/layout/CalendarShell.tsx +194 -192
- package/apps/shared/components/contacts/layout/ContactsShell.tsx +199 -197
- package/apps/shared/components/layout/AppShell.tsx +36 -18
- package/apps/shared/components/mail/layout/MailShell.tsx +420 -418
- package/apps/shared/components/settings/layout/SettingsShell.tsx +23 -9
- package/apps/shared/components/tasks/layout/TasksShell.tsx +201 -199
- package/apps/shared/plugins/pluginNav.ts +73 -0
- package/apps/shared/search/localIndexRpcClient.ts +3 -1
- package/dist/apps/admin/_404.d.ts +2 -0
- package/dist/apps/admin/_500.d.ts +2 -0
- package/dist/apps/admin/_layout.d.ts +8 -0
- package/dist/apps/admin/audit-log/index.d.ts +11 -0
- package/dist/apps/admin/branding/index.d.ts +3 -0
- package/dist/apps/admin/data-requests/index.d.ts +3 -0
- package/dist/apps/admin/distribution-lists/[uid].d.ts +7 -0
- package/dist/apps/admin/distribution-lists/index.d.ts +3 -0
- package/dist/apps/admin/distribution-lists/new/index.d.ts +3 -0
- package/dist/apps/admin/domains/[uid].d.ts +7 -0
- package/dist/apps/admin/domains/index.d.ts +3 -0
- package/dist/apps/admin/domains/new/index.d.ts +3 -0
- package/dist/apps/admin/encryption-policy/index.d.ts +3 -0
- package/dist/apps/admin/escrow-scopes/[uid].d.ts +21 -0
- package/dist/apps/admin/escrow-scopes/index.d.ts +3 -0
- package/dist/apps/admin/escrow-scopes/new/index.d.ts +3 -0
- package/dist/apps/admin/index.d.ts +3 -0
- package/dist/apps/admin/ingest-queue/index.d.ts +4 -0
- package/dist/apps/admin/mailbox-policy/index.d.ts +3 -0
- package/dist/apps/admin/mailboxes/[uid].d.ts +7 -0
- package/dist/apps/admin/mailboxes/new/index.d.ts +3 -0
- package/dist/apps/admin/plugins/index.d.ts +3 -0
- package/dist/apps/admin/quarantine/index.d.ts +6 -0
- package/dist/apps/admin/retention-policy/index.d.ts +3 -0
- package/dist/apps/admin/setup/index.d.ts +3 -0
- package/dist/apps/admin/transport-rules/[uid].d.ts +7 -0
- package/dist/apps/admin/transport-rules/_transportRuleConfig.d.ts +21 -0
- package/dist/apps/admin/transport-rules/index.d.ts +3 -0
- package/dist/apps/admin/transport-rules/new/index.d.ts +3 -0
- package/dist/apps/escrow/_layout.d.ts +10 -0
- package/dist/apps/escrow/audit-log/index.d.ts +9 -0
- package/dist/apps/escrow/index.d.ts +3 -0
- package/dist/apps/escrow/matters/[uid].d.ts +7 -0
- package/dist/apps/escrow/matters/new/index.d.ts +3 -0
- package/dist/apps/shared/components/admin/distributionLists/MemberListCard.d.ts +17 -0
- package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.d.ts +32 -0
- package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +32 -0
- package/dist/apps/shared/components/admin/layout/AdminShell.js +12 -5
- package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.d.ts +12 -0
- package/dist/apps/shared/components/admin/mailboxes/MailboxTable.d.ts +6 -0
- package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.d.ts +19 -0
- package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.d.ts +12 -0
- package/dist/apps/shared/components/admin/settings/BrandingForm.d.ts +9 -0
- package/dist/apps/shared/components/admin/settings/DomainDnsSetup.d.ts +12 -0
- package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.d.ts +12 -0
- package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.d.ts +9 -0
- package/dist/apps/shared/components/admin/settings/MailboxCreateForm.d.ts +19 -0
- package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.d.ts +10 -0
- package/dist/apps/shared/components/admin/settings/PluginsManager.d.ts +4 -0
- package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.d.ts +9 -0
- package/dist/apps/shared/components/admin/setup/EscrowSetupStep.d.ts +14 -0
- package/dist/apps/shared/components/admin/setup/SetupWizard.d.ts +36 -0
- package/dist/apps/shared/components/admin/signOut.d.ts +23 -0
- package/dist/apps/shared/components/admin/usePagedList.d.ts +39 -0
- package/dist/apps/shared/components/calendar/CalendarListSidebar.d.ts +26 -0
- package/dist/apps/shared/components/calendar/EventModal.d.ts +46 -0
- package/dist/apps/shared/components/calendar/MonthView.d.ts +15 -0
- package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +20 -0
- package/dist/apps/shared/components/calendar/ResourcePicker.d.ts +19 -0
- package/dist/apps/shared/components/calendar/SplitDayView.d.ts +28 -0
- package/dist/apps/shared/components/calendar/TimeGridView.d.ts +17 -0
- package/dist/apps/shared/components/calendar/allDay.d.ts +51 -0
- package/dist/apps/shared/components/calendar/layout/CalendarShell.d.ts +40 -0
- package/dist/apps/shared/components/calendar/layout/CalendarShell.js +2 -2
- package/dist/apps/shared/components/contacts/ContactDetailPane.d.ts +23 -0
- package/dist/apps/shared/components/contacts/ContactForm.d.ts +20 -0
- package/dist/apps/shared/components/contacts/ContactsSidebar.d.ts +40 -0
- package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +25 -0
- package/dist/apps/shared/components/contacts/KeyChangeReview.d.ts +40 -0
- package/dist/apps/shared/components/contacts/contactKeys.d.ts +29 -0
- package/dist/apps/shared/components/contacts/layout/ContactsShell.d.ts +21 -0
- package/dist/apps/shared/components/contacts/layout/ContactsShell.js +2 -2
- package/dist/apps/shared/components/escrow/layout/EscrowShell.d.ts +25 -0
- package/dist/apps/shared/components/forms/StringListField.d.ts +22 -0
- package/dist/apps/shared/components/layout/AppShell.d.ts +49 -0
- package/dist/apps/shared/components/layout/AppShell.js +15 -13
- package/dist/apps/shared/components/layout/BrandingChrome.d.ts +18 -0
- package/dist/apps/shared/components/layout/KeyEnrollmentGate.d.ts +51 -0
- package/dist/apps/shared/components/layout/MailboxProvisioning.d.ts +13 -0
- package/dist/apps/shared/components/layout/RecoveryCodeUnlock.d.ts +66 -0
- package/dist/apps/shared/components/layout/UnlockPromptProvider.d.ts +45 -0
- package/dist/apps/shared/components/layout/UserMenu.d.ts +23 -0
- package/dist/apps/shared/components/mail/ConversationList.d.ts +11 -0
- package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +23 -0
- package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +93 -0
- package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +58 -0
- package/dist/apps/shared/components/mail/compose/ComposeToolbar.d.ts +15 -0
- package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +37 -0
- package/dist/apps/shared/components/mail/compose/EmojiPicker.d.ts +14 -0
- package/dist/apps/shared/components/mail/compose/GifPicker.d.ts +13 -0
- package/dist/apps/shared/components/mail/compose/RichTextEditor.d.ts +34 -0
- package/dist/apps/shared/components/mail/compose/ScheduleSendPicker.d.ts +16 -0
- package/dist/apps/shared/components/mail/compose/composeFlushRegistry.d.ts +27 -0
- package/dist/apps/shared/components/mail/layout/MailShell.d.ts +57 -0
- package/dist/apps/shared/components/mail/layout/MailShell.js +2 -2
- package/dist/apps/shared/components/mail/pinnedSigners.d.ts +33 -0
- package/dist/apps/shared/components/mail/verificationSeals.d.ts +22 -0
- package/dist/apps/shared/components/mail/writableMailboxes.d.ts +15 -0
- package/dist/apps/shared/components/rules/RuleBuilder.d.ts +70 -0
- package/dist/apps/shared/components/settings/layout/SettingsShell.d.ts +41 -0
- package/dist/apps/shared/components/settings/layout/SettingsShell.js +19 -9
- package/dist/apps/shared/components/tasks/TasksSidebar.d.ts +41 -0
- package/dist/apps/shared/components/tasks/TasksToolbar.d.ts +14 -0
- package/dist/apps/shared/components/tasks/layout/TasksShell.d.ts +24 -0
- package/dist/apps/shared/components/tasks/layout/TasksShell.js +2 -2
- package/dist/apps/shared/mail/findWellKnownFolderUid.d.ts +5 -0
- package/dist/apps/shared/mail/listAllPages.d.ts +17 -0
- package/dist/apps/shared/plugins/pluginNav.d.ts +39 -0
- package/dist/apps/shared/plugins/pluginNav.js +33 -0
- package/dist/apps/shared/search/LocalIndexLifecycle.d.ts +13 -0
- package/dist/apps/shared/search/localIndexBlockCipher.d.ts +36 -0
- package/dist/apps/shared/search/localIndexBuilder.d.ts +85 -0
- package/dist/apps/shared/search/localIndexKey.d.ts +4 -0
- package/dist/apps/shared/search/localIndexRpcClient.d.ts +71 -0
- package/dist/apps/shared/search/localIndexRpcClient.js +3 -1
- package/dist/apps/shared/search/localIndexSchema.d.ts +111 -0
- package/dist/apps/shared/search/localIndexSizePreference.d.ts +27 -0
- package/dist/apps/shared/search/localIndexStorage.d.ts +28 -0
- package/dist/apps/shared/search/localIndexVFS.d.ts +101 -0
- package/dist/apps/shared/search/localIndexWorker.d.ts +145 -0
- package/dist/apps/shared/search/searchTier2.d.ts +30 -0
- package/dist/apps/www/_404.d.ts +2 -0
- package/dist/apps/www/_500.d.ts +2 -0
- package/dist/apps/www/_layout.d.ts +14 -0
- package/dist/apps/www/calendar/index.d.ts +3 -0
- package/dist/apps/www/contacts/[uid].d.ts +13 -0
- package/dist/apps/www/contacts/index.d.ts +3 -0
- package/dist/apps/www/index.d.ts +3 -0
- package/dist/apps/www/messages/[uid].d.ts +11 -0
- package/dist/apps/www/settings/auto-reply/index.d.ts +4 -0
- package/dist/apps/www/settings/encryption/index.d.ts +7 -0
- package/dist/apps/www/settings/filters/[uid].d.ts +8 -0
- package/dist/apps/www/settings/filters/_mailFilterRuleConfig.d.ts +11 -0
- package/dist/apps/www/settings/filters/index.d.ts +4 -0
- package/dist/apps/www/settings/filters/new/index.d.ts +4 -0
- package/dist/apps/www/settings/focused-inbox/index.d.ts +4 -0
- package/dist/apps/www/settings/labels/index.d.ts +4 -0
- package/dist/apps/www/settings/privacy/index.d.ts +4 -0
- package/dist/apps/www/settings/read-receipts/index.d.ts +4 -0
- package/dist/apps/www/settings/sharing/index.d.ts +4 -0
- package/dist/apps/www/settings/signatures/[uid].d.ts +8 -0
- package/dist/apps/www/settings/signatures/index.d.ts +4 -0
- package/dist/apps/www/settings/signatures/new/index.d.ts +4 -0
- package/dist/apps/www/settings/signatures/signatureDefaults.d.ts +10 -0
- package/dist/apps/www/tasks/index.d.ts +3 -0
- package/package.json +3 -3
- package/apps/shared/components/booking/AvailabilityEditor.tsx +0 -118
- package/apps/www/settings/booking-types/[uid].tsx +0 -306
- package/apps/www/settings/booking-types/index.tsx +0 -98
- package/apps/www/settings/booking-types/new/index.tsx +0 -212
- package/dist/apps/shared/components/booking/AvailabilityEditor.js +0 -45
- package/dist/apps/www/settings/booking-types/[uid].js +0 -134
- package/dist/apps/www/settings/booking-types/index.js +0 -29
- package/dist/apps/www/settings/booking-types/new/index.js +0 -86
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { EscrowScope, EscrowScopePublicKey } from "@rapidmx/react-shared/admin/escrowScopesApi.js";
|
|
3
|
+
import { AdminShellProps } from "../../shared/components/admin/layout/AdminShell.js";
|
|
4
|
+
import { EscrowScopeKeyAndHoldersValue } from "../../shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js";
|
|
5
|
+
/**
|
|
6
|
+
* Describes every change to the security-relevant parts of a scope - who holds it, how many holders must approve,
|
|
7
|
+
* and its public key - so the administrator confirms exactly what they're changing before it's saved.
|
|
8
|
+
*/
|
|
9
|
+
export declare function describeSecurityChanges(original: EscrowScope, next: EscrowScopeKeyAndHoldersValue): string[];
|
|
10
|
+
/**
|
|
11
|
+
* The `publicKey` to send with an update, or `undefined` when the admin didn't touch any key field - the form only
|
|
12
|
+
* shows dates to the minute, so re-sending a rebuilt key would silently truncate the stored validity window. A date
|
|
13
|
+
* field left as loaded keeps its original epoch-ms value. `revokedAt` isn't editable here: it's carried over when
|
|
14
|
+
* only the validity window changed, and dropped when the key material itself is replaced (a new key isn't revoked).
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildPublicKeyUpdate(original: EscrowScope, next: EscrowScopeKeyAndHoldersValue): EscrowScopePublicKey | undefined;
|
|
17
|
+
export default function EscrowScopeDetailPage(props: Omit<AdminShellProps, "active"> & {
|
|
18
|
+
params: {
|
|
19
|
+
uid: string;
|
|
20
|
+
};
|
|
21
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { AdminShellProps } from "../../shared/components/admin/layout/AdminShell.js";
|
|
3
|
+
export declare function readMailboxUid(): string | null;
|
|
4
|
+
export default function IngestQueuePage(props: Omit<AdminShellProps, "active">): React.JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { AdminShellProps } from "../../shared/components/admin/layout/AdminShell.js";
|
|
3
|
+
export declare function readMailboxUid(): string | null;
|
|
4
|
+
export default function QuarantinePage(props: Omit<AdminShellProps, "active"> & {
|
|
5
|
+
userUid?: string;
|
|
6
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { TransportRuleAction, TransportRuleConditions } from "@rapidmx/react-shared/admin/transportRulesApi.js";
|
|
3
|
+
import { ActionTypeDef, ConditionFieldDef } from "../../shared/components/rules/RuleBuilder.js";
|
|
4
|
+
/** Refused outright when a rule has no conditions: it would reject or quarantine every message the server receives. */
|
|
5
|
+
export declare const NO_CONDITIONS_BLOCKED_MESSAGE = "Add at least one condition. A rule without conditions that rejects or quarantines mail would do so for every message.";
|
|
6
|
+
/**
|
|
7
|
+
* How a save should proceed given a rule's conditions: `"ok"` with at least one condition, `"blocked"` with none and a
|
|
8
|
+
* reject/quarantine action, or `"confirm"` with none and only other actions (which then apply to every message).
|
|
9
|
+
*/
|
|
10
|
+
export declare function checkRuleConditions(rule: {
|
|
11
|
+
conditions: TransportRuleConditions;
|
|
12
|
+
actions: TransportRuleAction[];
|
|
13
|
+
}): "ok" | "blocked" | "confirm";
|
|
14
|
+
/** Asks before saving a rule with no conditions whose actions will run on every message. */
|
|
15
|
+
export declare function NoConditionsConfirmModal({ open, onCancel, onConfirm }: {
|
|
16
|
+
open: boolean;
|
|
17
|
+
onCancel: () => void;
|
|
18
|
+
onConfirm: () => void;
|
|
19
|
+
}): React.JSX.Element;
|
|
20
|
+
export declare const TRANSPORT_RULE_CONDITION_FIELDS: ConditionFieldDef[];
|
|
21
|
+
export declare const TRANSPORT_RULE_ACTION_TYPES: ActionTypeDef<TransportRuleAction>[];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React, { PropsWithChildren } from "react";
|
|
2
|
+
import { Branding } from "@rapidmx/react-shared/branding/brandingApi.js";
|
|
3
|
+
export interface LayoutProps {
|
|
4
|
+
/** See `apps/www/_layout.tsx`'s `LayoutProps` doc comment — identical mechanism, supplied by
|
|
5
|
+
* `EscrowConsoleRoute`'s `fetchProps()`. */
|
|
6
|
+
branding?: Branding;
|
|
7
|
+
}
|
|
8
|
+
/** Unlike the other apps, never links the admin-configured custom stylesheet: the escrow console handles escrow
|
|
9
|
+
* key material, so no admin-supplied CSS is loaded on it. */
|
|
10
|
+
export default function Layout({ children, branding }: PropsWithChildren<LayoutProps>): React.JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { EscrowAuditVerificationResult } from "@rapidmx/react-shared/admin/escrowAuditLogApi.js";
|
|
3
|
+
import { EscrowShellProps } from "../../shared/components/escrow/layout/EscrowShell.js";
|
|
4
|
+
/** The label for an audit action - the raw action name for one this console doesn't know yet (a newer server). */
|
|
5
|
+
export declare function actionLabel(action: string): string;
|
|
6
|
+
/** Explains a failed chain verification by its `reason` (plus where it broke, when known). An unrecognized or missing
|
|
7
|
+
* reason (a newer or older server) reads as a generic failure. */
|
|
8
|
+
export declare function describeVerificationFailure(result: EscrowAuditVerificationResult): string;
|
|
9
|
+
export default function EscrowAuditLogPage(props: Omit<EscrowShellProps, "active">): React.JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { DistributionList } from "@rapidmx/react-shared/admin/distributionListsApi.js";
|
|
3
|
+
export interface MemberListCardProps {
|
|
4
|
+
list: DistributionList;
|
|
5
|
+
/** Called with the freshly-saved list (new `version`, updated `memberAddresses`) after a successful
|
|
6
|
+
* add/remove, so the parent detail page can keep its own copy of the list in sync — mirrors
|
|
7
|
+
* `ShareAccessCard`'s `reload()` pattern, just pushed up rather than re-fetched, since the caller
|
|
8
|
+
* already has everything the response would return. */
|
|
9
|
+
onUpdate: (list: DistributionList) => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Lets an admin view and edit a distribution list's members — same load/inline-add-row/per-row-remove
|
|
13
|
+
* interaction shape as `ShareAccessCard`, but against a plain `memberAddresses: string[]` field on the
|
|
14
|
+
* `DistributionList` itself via read-modify-write `PUT`, not a separate ACL endpoint (a distribution
|
|
15
|
+
* list has no per-record ACL to speak of — see `BaseDistributionListRoute`'s own doc comment).
|
|
16
|
+
*/
|
|
17
|
+
export default function MemberListCard({ list, onUpdate }: MemberListCardProps): React.JSX.Element;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/** The part of an `EscrowScope` shared by the "new" and "[uid]" pages — everything except `name`/
|
|
3
|
+
* `description`, which stay plain inline `FormField`s on each page (same split `distribution-lists`
|
|
4
|
+
* already uses: simple top-level fields inline, the more involved sub-structure factored out). An admin
|
|
5
|
+
* pastes in the fields of an already-issued certificate here; nothing in this app generates a keypair —
|
|
6
|
+
* see `EscrowScopePublicKey`'s own doc comment in `escrowScopesApi.ts`. */
|
|
7
|
+
export interface EscrowScopeKeyAndHoldersValue {
|
|
8
|
+
publicKey: string;
|
|
9
|
+
keyType: string;
|
|
10
|
+
fingerprint: string;
|
|
11
|
+
/** `<input type="datetime-local">` value — see `toDatetimeLocal()`. */
|
|
12
|
+
notBefore: string;
|
|
13
|
+
notAfter: string;
|
|
14
|
+
holderUserUids: string[];
|
|
15
|
+
requiredHolders: number;
|
|
16
|
+
notifySubjectOnAccess: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface EscrowScopeKeyAndHoldersFieldsProps {
|
|
19
|
+
value: EscrowScopeKeyAndHoldersValue;
|
|
20
|
+
onChange: (value: EscrowScopeKeyAndHoldersValue) => void;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
/** Shows the public key fields without letting them be edited, e.g. for keys generated in the browser. */
|
|
23
|
+
keyReadOnly?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/** Builds an all-zeroes starting point for the "new" page — `notBefore`/`notAfter` default to "now" so an
|
|
26
|
+
* admin pasting in a cert's own dates only has to touch what actually differs. */
|
|
27
|
+
export declare function emptyEscrowScopeKeyAndHoldersValue(): EscrowScopeKeyAndHoldersValue;
|
|
28
|
+
/** The message shown when an administrator tries to make themselves a holder: whoever configures a scope must not
|
|
29
|
+
* also be able to approve access under it (separation of duties - the server refuses it too). Holders who were
|
|
30
|
+
* already on the scope (`existingHolderUserUids`) aren't treated as newly added. */
|
|
31
|
+
export declare function selfAsHolderError(holderUserUids: string[], adminUid: string | undefined, existingHolderUserUids?: string[]): string | null;
|
|
32
|
+
export default function EscrowScopeKeyAndHoldersFields({ value, onChange, disabled, keyReadOnly }: EscrowScopeKeyAndHoldersFieldsProps): React.JSX.Element;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import "../../../styles/app.css";
|
|
2
|
+
import React, { PropsWithChildren } from "react";
|
|
3
|
+
import { NavItem } from "@rapidmx/react-shared/components/navigation/BottomTabBar.js";
|
|
4
|
+
import { PluginNav, PluginNavProps } from "../../../plugins/pluginNav.js";
|
|
5
|
+
export type AdminSection = "mailboxes" | "quarantine" | "ingestQueue" | "domains" | "auditLog" | "distributionLists" | "transportRules" | "escrowScopes" | "retentionPolicy" | "encryptionPolicy" | "mailboxPolicy" | "setup" | "dataRequests" | "plugins" | "branding";
|
|
6
|
+
/** A core `AdminSection`, or a plugin's `adminNav` item id (see `PluginNav`). */
|
|
7
|
+
export type AdminShellActive = AdminSection | (string & {});
|
|
8
|
+
export interface AdminShellProps extends PluginNavProps {
|
|
9
|
+
/** Which icon in the rail is highlighted as the current section - a plugin admin page passes its own
|
|
10
|
+
* `adminNav` item id. */
|
|
11
|
+
active: AdminShellActive;
|
|
12
|
+
/** Populated automatically by the framework from an authenticated request (e.g. a valid `jwt` cookie). */
|
|
13
|
+
userUid?: string;
|
|
14
|
+
/** auth-server's base URL, injected via the route's `fetchProps` — see `src/mongo/routes/AdminConsoleRoute.ts`. */
|
|
15
|
+
authServerUrl?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Where `mailApi.ts`'s `impersonateUser()`/`stopImpersonating()` should call: the real auth-server in
|
|
18
|
+
* production, or `""` under `yarn dev` to call this app's own local dev-only impersonation endpoint
|
|
19
|
+
* instead — see `AdminConsoleRoute`'s `fetchProps` and `src/dev/DevImpersonationRoute.ts`.
|
|
20
|
+
*/
|
|
21
|
+
impersonationBaseUrl?: string;
|
|
22
|
+
}
|
|
23
|
+
/** `NAV_ITEMS` followed by the plugins' `adminNav` items (generic icon). Core ids win, including the
|
|
24
|
+
* off-rail sections' - see `mergePluginNavItems`. */
|
|
25
|
+
export declare function adminNavItems(pluginNav?: PluginNav): NavItem[];
|
|
26
|
+
/**
|
|
27
|
+
* Gates every `apps/admin` page behind the `admin` trusted role. Uses `GET /api/admin/release-notes` (any
|
|
28
|
+
* `BaseAdminRoute` endpoint works — this one is side-effect-free) purely as a canary: a 200 means the
|
|
29
|
+
* caller's JWT carries a trusted role, a 403 means it doesn't. There is no local step-up/elevation flow
|
|
30
|
+
* (that would need a cross-origin call to auth-server's own elevation endpoint — not wired up yet).
|
|
31
|
+
*/
|
|
32
|
+
export default function AdminShell({ active, userUid, authServerUrl, pluginNav, children }: PropsWithChildren<AdminShellProps>): React.JSX.Element;
|
|
@@ -15,6 +15,7 @@ import BottomTabBar from "@rapidmx/react-shared/components/navigation/BottomTabB
|
|
|
15
15
|
import { BrandingFooter, BrandingHeader } from "../../layout/BrandingChrome.js";
|
|
16
16
|
import UserMenu from "../../layout/UserMenu.js";
|
|
17
17
|
import { signOutOfConsole } from "../signOut.js";
|
|
18
|
+
import { mergePluginNavItems } from "../../../plugins/pluginNav.js";
|
|
18
19
|
/** Sections shown in the persistent icon rail / mobile tab bar — every admin area reachable from
|
|
19
20
|
* anywhere in the console. Deliberately excludes `quarantine`/`ingestQueue`: those are scoped to a
|
|
20
21
|
* single mailbox and only ever reached via links on that mailbox's own detail page (see
|
|
@@ -76,14 +77,19 @@ const MAILBOX_SCOPED_ITEMS = [
|
|
|
76
77
|
];
|
|
77
78
|
/** The setup wizard - reached by redirect or from the Mailboxes page, not from the rail. */
|
|
78
79
|
const SETUP_ITEM = { id: "setup", href: "/admin/setup", label: "Setup", icon: HiOutlineRocketLaunch };
|
|
79
|
-
const
|
|
80
|
+
const OFF_RAIL_ITEMS = [...MAILBOX_SCOPED_ITEMS, SETUP_ITEM];
|
|
81
|
+
/** `NAV_ITEMS` followed by the plugins' `adminNav` items (generic icon). Core ids win, including the
|
|
82
|
+
* off-rail sections' - see `mergePluginNavItems`. */
|
|
83
|
+
export function adminNavItems(pluginNav) {
|
|
84
|
+
return mergePluginNavItems(NAV_ITEMS, pluginNav?.adminNav, ({ id, href, label }) => ({ id, href, label, icon: HiOutlinePuzzlePiece }), OFF_RAIL_ITEMS.map((item) => item.id));
|
|
85
|
+
}
|
|
80
86
|
/**
|
|
81
87
|
* Gates every `apps/admin` page behind the `admin` trusted role. Uses `GET /api/admin/release-notes` (any
|
|
82
88
|
* `BaseAdminRoute` endpoint works — this one is side-effect-free) purely as a canary: a 200 means the
|
|
83
89
|
* caller's JWT carries a trusted role, a 403 means it doesn't. There is no local step-up/elevation flow
|
|
84
90
|
* (that would need a cross-origin call to auth-server's own elevation endpoint — not wired up yet).
|
|
85
91
|
*/
|
|
86
|
-
export default function AdminShell({ active, userUid, authServerUrl, children }) {
|
|
92
|
+
export default function AdminShell({ active, userUid, authServerUrl, pluginNav, children }) {
|
|
87
93
|
const [status, setStatus] = useState("checking");
|
|
88
94
|
const [error, setError] = useState(null);
|
|
89
95
|
const { branding, iconSrc } = useBranding();
|
|
@@ -133,13 +139,14 @@ export default function AdminShell({ active, userUid, authServerUrl, children })
|
|
|
133
139
|
content = (_jsx("div", { className: "min-h-screen flex items-center justify-center p-8", children: _jsx("div", { className: "w-full max-w-md", children: _jsx(Alert, { children: error }) }) }));
|
|
134
140
|
}
|
|
135
141
|
else {
|
|
136
|
-
const
|
|
137
|
-
|
|
142
|
+
const navItems = adminNavItems(pluginNav);
|
|
143
|
+
const activeItem = [...navItems, ...OFF_RAIL_ITEMS].find((item) => item.id === active);
|
|
144
|
+
content = (_jsx("div", { className: "min-h-screen flex flex-col bg-surface-alt", children: _jsxs("div", { className: "flex-1 flex min-h-0", children: [_jsxs("nav", { "aria-label": "Admin sections", className: "hidden md:flex w-16 shrink-0 bg-surface border-r border-border flex-col items-center py-3 gap-1", children: [_jsx("img", { src: iconSrc, width: "96", height: "96", alt: "", className: "mb-3" }), navItems.map(({ id, href, label, icon: Icon }) => (_jsx("a", { href: href, "aria-label": label, "aria-current": id === active ? "page" : undefined, title: label, className: [
|
|
138
145
|
"w-10 h-10 flex items-center justify-center rounded-sm",
|
|
139
146
|
id === active
|
|
140
147
|
? "bg-primary/10 text-primary-dark"
|
|
141
148
|
: "text-text-muted hover:bg-surface-alt hover:text-text",
|
|
142
|
-
].join(" "), children: _jsx(Icon, { size: 20, "aria-hidden": "true" }) }, id)))] }), _jsx(BottomTabBar, { apps:
|
|
149
|
+
].join(" "), children: _jsx(Icon, { size: 20, "aria-hidden": "true" }) }, id)))] }), _jsx(BottomTabBar, { apps: navItems, active: active }), _jsxs("div", { className: "flex-1 flex flex-col min-w-0", children: [_jsxs("header", { className: "h-16 shrink-0 bg-surface border-b border-border flex items-center justify-between gap-4 px-6", children: [_jsx("span", { className: "font-display font-bold text-lg uppercase tracking-wide", children: activeItem?.label }), _jsx(UserMenu, { userUid: userUid, authServerUrl: authServerUrl, onSignOut: handleSignOut })] }), _jsx("div", { className: "flex-1 pb-14 md:pb-0", children: _jsx("main", { className: "max-w-6xl mx-auto px-6 py-8", children: children }) })] })] }) }));
|
|
143
150
|
}
|
|
144
151
|
return (_jsxs(_Fragment, { children: [_jsx(BrandingHeader, { branding: branding }), content, _jsx(BrandingFooter, { branding: branding })] }));
|
|
145
152
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Mailbox } from "@rapidmx/react-shared/mail/mailApi.js";
|
|
3
|
+
export interface EscrowScopeCardProps {
|
|
4
|
+
mailbox: Mailbox;
|
|
5
|
+
/** Called with the saved mailbox, same push-up pattern as `ResourceSettingsCard`. */
|
|
6
|
+
onUpdate: (mailbox: Mailbox) => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Assigns a mailbox to an escrow scope (or none), which decides whose holders can recover its encrypted mail. Only
|
|
10
|
+
* shown in the admin console, whose trusted-role gate the server enforces again for `escrowScopeId`.
|
|
11
|
+
*/
|
|
12
|
+
export default function EscrowScopeCard({ mailbox, onUpdate }: EscrowScopeCardProps): React.JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Mailbox } from "@rapidmx/react-shared/mail/mailApi.js";
|
|
3
|
+
export interface ResourceSettingsCardProps {
|
|
4
|
+
mailbox: Mailbox;
|
|
5
|
+
/** Called with the freshly-saved mailbox after a successful save — mirrors `MemberListCard`'s
|
|
6
|
+
* identical push-up-rather-than-reload pattern, since the caller already has everything the
|
|
7
|
+
* response would return. */
|
|
8
|
+
onUpdate: (mailbox: Mailbox) => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Lets an admin view and edit a resource mailbox's booking settings — same load/edit/PUT/reload
|
|
12
|
+
* interaction shape as `ShareAccessCard`, adapted the same way `MemberListCard` already adapted it:
|
|
13
|
+
* these seven fields live directly on the `Mailbox` the parent detail page already loaded (not a
|
|
14
|
+
* separate resource fetched by its own endpoint, unlike a mailbox's ACL), so this receives the
|
|
15
|
+
* already-loaded `mailbox` and pushes the `PUT` response back up rather than fetching independently.
|
|
16
|
+
* Only rendered by the detail page when `mailbox.isResource` is already `true` — a mailbox becomes a
|
|
17
|
+
* resource at creation time (`apps/admin/mailboxes/new`), not retroactively from here.
|
|
18
|
+
*/
|
|
19
|
+
export default function ResourceSettingsCard({ mailbox, onUpdate }: ResourceSettingsCardProps): React.JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface ShareAccessCardProps {
|
|
3
|
+
mailboxUid: string;
|
|
4
|
+
/** The mailbox's owner - their own grant is shown but can't be revoked from here. */
|
|
5
|
+
ownerUserUid?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Lets an admin (or, eventually, the mailbox owner) view and edit a mailbox's delegate access — the
|
|
9
|
+
* mechanism behind Exchange-style shared mailboxes. `records` on a mailbox's own ACL doubles as both the
|
|
10
|
+
* owner's grant (if any) and every delegate's — see `BaseMailboxRoute`'s doc comment in `@rapidmx/restapi`.
|
|
11
|
+
*/
|
|
12
|
+
export default function ShareAccessCard({ mailboxUid, ownerUserUid }: ShareAccessCardProps): React.JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Branding } from "@rapidmx/react-shared/branding/brandingApi.js";
|
|
3
|
+
/** SVG logo/icon uploads are refused (the server refuses them too): an SVG served from this origin can carry script. */
|
|
4
|
+
export declare function isSvgFile(file: File): boolean;
|
|
5
|
+
/** The branding editor, shared by the Branding page and the setup wizard. */
|
|
6
|
+
export default function BrandingForm({ branding, onChange }: {
|
|
7
|
+
branding: Branding;
|
|
8
|
+
onChange: (b: Branding) => void;
|
|
9
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Domain } from "@rapidmx/react-shared/admin/domainsApi.js";
|
|
3
|
+
export interface DomainDnsSetupProps {
|
|
4
|
+
uid: string;
|
|
5
|
+
/** Called with the domain every time it's (re)loaded - e.g. after "Verify now". */
|
|
6
|
+
onLoaded?: (domain: Domain) => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A domain's status, its ownership TXT record with "Verify now", and the DNS setup checklist - shared by the domain
|
|
10
|
+
* detail page and the setup wizard.
|
|
11
|
+
*/
|
|
12
|
+
export default function DomainDnsSetup({ uid, onLoaded }: DomainDnsSetupProps): React.JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { EncryptionPolicy } from "@rapidmx/react-shared/crypto/keyvaultApi.js";
|
|
3
|
+
/** Whether end-to-end encryption can be used at all under `policy` - i.e. any tier allows it. */
|
|
4
|
+
export declare function isEncryptionEnabled(policy: EncryptionPolicy): boolean;
|
|
5
|
+
export interface EncryptionPolicyFormProps {
|
|
6
|
+
policy: EncryptionPolicy;
|
|
7
|
+
onChange: (policy: EncryptionPolicy) => void;
|
|
8
|
+
/** Told whether the form has edits that haven't been saved. */
|
|
9
|
+
onDirtyChange?: (dirty: boolean) => void;
|
|
10
|
+
}
|
|
11
|
+
/** The end-to-end encryption policy editor, shared by the Encryption Policy page and the setup wizard. */
|
|
12
|
+
export default function EncryptionPolicyForm({ policy, onChange, onDirtyChange }: EncryptionPolicyFormProps): React.JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
|
+
export interface LoadedSettingsFormProps<T> {
|
|
3
|
+
load: () => Promise<T>;
|
|
4
|
+
/** Shown when loading fails with something other than an API error message. */
|
|
5
|
+
loadErrorMessage: string;
|
|
6
|
+
children: (value: T, onChange: (value: T) => void) => ReactNode;
|
|
7
|
+
}
|
|
8
|
+
/** Loads a settings object, then renders its form - the loading and error states every settings page shares. */
|
|
9
|
+
export default function LoadedSettingsForm<T>({ load, loadErrorMessage, children }: LoadedSettingsFormProps<T>): React.JSX.Element;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Mailbox } from "@rapidmx/react-shared/mail/mailApi.js";
|
|
3
|
+
export interface MailboxCreateFormProps {
|
|
4
|
+
onCreated: (mailbox: Mailbox) => void;
|
|
5
|
+
/** Initial field values, e.g. the signed-in admin's own mailbox in the setup wizard. */
|
|
6
|
+
defaults?: {
|
|
7
|
+
localPart?: string;
|
|
8
|
+
domain?: string;
|
|
9
|
+
displayName?: string;
|
|
10
|
+
ownerUserUid?: string;
|
|
11
|
+
};
|
|
12
|
+
submitLabel?: string;
|
|
13
|
+
cancelHref?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The "New mailbox" form, shared by the New Mailbox page and the setup wizard. The quota starts at the mailbox
|
|
17
|
+
* policy's default.
|
|
18
|
+
*/
|
|
19
|
+
export default function MailboxCreateForm({ onCreated, defaults, submitLabel, cancelHref }: MailboxCreateFormProps): React.JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { MailboxPolicy } from "@rapidmx/react-shared/admin/mailboxPolicyApi.js";
|
|
3
|
+
export interface MailboxPolicyFormProps {
|
|
4
|
+
policy: MailboxPolicy;
|
|
5
|
+
onChange: (policy: MailboxPolicy) => void;
|
|
6
|
+
/** Told whether the form has edits that haven't been saved. */
|
|
7
|
+
onDirtyChange?: (dirty: boolean) => void;
|
|
8
|
+
}
|
|
9
|
+
/** The mailbox defaults editor, shared by the Mailbox Policy page and the setup wizard. */
|
|
10
|
+
export default function MailboxPolicyForm({ policy, onChange, onDirtyChange }: MailboxPolicyFormProps): React.JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { RetentionPolicy } from "@rapidmx/react-shared/admin/retentionPolicyApi.js";
|
|
3
|
+
/** The retention policy editor, shared by the Retention Policy page and the setup wizard. */
|
|
4
|
+
export default function RetentionPolicyForm({ policy, onChange, onDirtyChange, }: {
|
|
5
|
+
policy: RetentionPolicy;
|
|
6
|
+
onChange: (p: RetentionPolicy) => void;
|
|
7
|
+
/** Told whether the form has edits that haven't been saved. */
|
|
8
|
+
onDirtyChange?: (dirty: boolean) => void;
|
|
9
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
/** How long a download's object URL is kept, since some browsers are still reading it after the click returns. */
|
|
3
|
+
export declare const DOWNLOAD_URL_LIFETIME_MS = 60000;
|
|
4
|
+
/** Offers `text` to the browser as a file download. */
|
|
5
|
+
export declare function downloadTextFile(filename: string, text: string, type?: string): void;
|
|
6
|
+
/**
|
|
7
|
+
* The setup wizard's escrow step. Escrow lets a separate group of holders recover a mailbox's encrypted mail (for
|
|
8
|
+
* example for legal discovery) using a key this server never has. It's optional, and the administrator can either
|
|
9
|
+
* generate the key pair here (downloading the private key, which never leaves the browser), paste in an existing
|
|
10
|
+
* certificate, or go without escrow.
|
|
11
|
+
*/
|
|
12
|
+
export default function EscrowSetupStep({ adminUid }: {
|
|
13
|
+
adminUid?: string;
|
|
14
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export declare const SETUP_STEPS: readonly [{
|
|
3
|
+
readonly id: "plugins";
|
|
4
|
+
readonly title: "Plugins";
|
|
5
|
+
readonly intro: "Choose which protocols and features this server runs. The recommended plugins are already installed.";
|
|
6
|
+
}, {
|
|
7
|
+
readonly id: "domain";
|
|
8
|
+
readonly title: "Domain";
|
|
9
|
+
readonly intro: "Add the domain this server receives mail for, then publish the DNS records below.";
|
|
10
|
+
}, {
|
|
11
|
+
readonly id: "settings";
|
|
12
|
+
readonly title: "Server settings";
|
|
13
|
+
readonly intro: "Set the rules for encryption, how long mail is kept, and new mailboxes.";
|
|
14
|
+
}, {
|
|
15
|
+
readonly id: "escrow";
|
|
16
|
+
readonly title: "Escrow";
|
|
17
|
+
readonly intro: "Decide whether encrypted mail can be recovered by a trusted group of holders.";
|
|
18
|
+
}, {
|
|
19
|
+
readonly id: "branding";
|
|
20
|
+
readonly title: "Branding";
|
|
21
|
+
readonly intro: "Make the sign-in page and apps look like your organization.";
|
|
22
|
+
}, {
|
|
23
|
+
readonly id: "mailboxes";
|
|
24
|
+
readonly title: "Mailboxes";
|
|
25
|
+
readonly intro: "Create the first mailboxes, starting with your own.";
|
|
26
|
+
}];
|
|
27
|
+
export type SetupStepId = (typeof SETUP_STEPS)[number]["id"];
|
|
28
|
+
export interface SetupWizardProps {
|
|
29
|
+
userUid: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The first-run setup wizard. Each step saves as the administrator works through it; the wizard itself only records
|
|
33
|
+
* which step they're on (so leaving and coming back resumes there) and, at the end, that setup is finished. Every step
|
|
34
|
+
* except the domain can be passed over and configured later from the admin console.
|
|
35
|
+
*/
|
|
36
|
+
export default function SetupWizard({ userUid }: SetupWizardProps): React.JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cross-tab sign-out channel - must stay identical to `SIGN_OUT_CHANNEL` in
|
|
3
|
+
* `apps/shared/search/localIndexRpcClient.ts` (the channel `AppShell` listens on and `destroyAllLocalIndexes()`
|
|
4
|
+
* announces on). Duplicated rather than imported so the admin/escrow consoles don't pull the local-search Worker
|
|
5
|
+
* client into their bundles; `test/apps/admin/_components/signOut.test.ts` fails if the two ever drift apart.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CONSOLE_SIGN_OUT_CHANNEL = "rapidmx-localsearch";
|
|
8
|
+
/** How long sign-out waits for auth-server's logout before navigating anyway (same bound as `AppShell`). */
|
|
9
|
+
export declare const CONSOLE_LOGOUT_TIMEOUT_MS = 3000;
|
|
10
|
+
/**
|
|
11
|
+
* The local search index's pending-deletions `localStorage` key - must stay identical to `PENDING_DELETIONS_KEY`
|
|
12
|
+
* in `apps/shared/search/localIndexRpcClient.ts`, duplicated for the same bundle reason as the channel above
|
|
13
|
+
* (the test checks it). `"*"` is that module's "every index on this device" entry.
|
|
14
|
+
*/
|
|
15
|
+
export declare const CONSOLE_PENDING_DELETIONS_KEY = "rapidmx-localsearch-pending-deletions";
|
|
16
|
+
/**
|
|
17
|
+
* Sign-out for `AdminShell`/`EscrowShell`: announces the sign-out to other tabs, ends the auth-server session
|
|
18
|
+
* (clears the auth cookie and invalidates the refresh token - navigating alone would leave the session valid),
|
|
19
|
+
* then navigates to auth-server (or `/`). Mirrors `AppShell.handleSignOut`, except that the consoles hold no
|
|
20
|
+
* unlocked keys and can't delete local search indexes in their own tab: they record every index for deletion
|
|
21
|
+
* (finished by the next mail page load) and rely on an open mail tab hearing the broadcast to delete them now.
|
|
22
|
+
*/
|
|
23
|
+
export declare function signOutOfConsole(authServerUrl: string | undefined): Promise<void>;
|