@rapidmx/web-client 0.27.0 → 0.29.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 +3 -0
- package/apps/shared/components/admin/diagnostics/DiagnosticsManager.tsx +22 -10
- package/apps/shared/components/admin/diagnostics/InformationPanel.tsx +60 -0
- package/apps/shared/components/admin/diagnostics/SettingsTable.tsx +108 -0
- package/apps/shared/components/admin/diagnostics/diagnosticsApi.ts +25 -1
- package/apps/shared/components/calendar/CalendarSearchBox.tsx +83 -0
- package/apps/shared/components/calendar/EventMatchNav.tsx +72 -0
- package/apps/shared/components/calendar/EventModal.tsx +33 -12
- package/apps/shared/components/calendar/ListView.tsx +207 -0
- package/apps/shared/components/calendar/MonthView.tsx +14 -2
- package/apps/shared/components/calendar/SlideIn.tsx +47 -0
- package/apps/shared/components/calendar/SplitDayView.tsx +5 -0
- package/apps/shared/components/calendar/TimeGridView.tsx +23 -12
- package/apps/shared/components/calendar/activeOccurrence.ts +28 -0
- package/apps/shared/components/calendar/allDay.ts +16 -1
- package/apps/shared/components/calendar/calendarView.ts +41 -0
- package/apps/shared/components/layout/AppShell.tsx +13 -6
- package/apps/shared/components/mail/ConversationList.tsx +32 -6
- package/apps/shared/components/mail/ConversationThreadPane.tsx +15 -0
- package/apps/shared/components/mail/MailSelectionBar.tsx +117 -55
- package/apps/shared/components/mail/MessageDetailPane.tsx +3 -0
- package/apps/shared/components/mail/compose/ComposeContext.tsx +193 -35
- package/apps/shared/components/mail/compose/ComposeWindow.tsx +62 -11
- package/apps/shared/components/mail/compose/ComposeWindowPlaceholder.tsx +21 -10
- package/apps/shared/components/mail/compose/RichTextEditor.tsx +2 -1
- package/apps/shared/components/mail/compose/quotedBody.ts +45 -2
- package/apps/shared/components/mail/labelMenu.tsx +4 -0
- package/apps/shared/components/mail/layout/MailShell.tsx +9 -2
- package/apps/shared/components/mail/reading/MessageBody.tsx +1 -1
- package/apps/shared/components/mail/reading/bodyContent.ts +15 -13
- package/apps/shared/components/mail/reading/bodyHtml.ts +12 -7
- package/apps/shared/gestures/useEnterSlide.ts +1 -1
- package/apps/shared/keyboard/keymap.ts +2 -0
- package/apps/shared/mail/rangeSelection.ts +45 -0
- package/apps/shared/mail/rowExit.ts +39 -0
- package/apps/shared/mail/usePermanentDelete.tsx +14 -7
- package/apps/www/calendar/index.tsx +251 -53
- package/apps/www/index.tsx +563 -376
- package/dist/apps/shared/components/admin/diagnostics/DiagnosticsManager.d.ts +3 -3
- package/dist/apps/shared/components/admin/diagnostics/DiagnosticsManager.js +15 -9
- package/dist/apps/shared/components/admin/diagnostics/InformationPanel.d.ts +15 -0
- package/dist/apps/shared/components/admin/diagnostics/InformationPanel.js +16 -0
- package/dist/apps/shared/components/admin/diagnostics/SettingsTable.d.ts +20 -0
- package/dist/apps/shared/components/admin/diagnostics/SettingsTable.js +31 -0
- package/dist/apps/shared/components/admin/diagnostics/diagnosticsApi.d.ts +20 -1
- package/dist/apps/shared/components/admin/diagnostics/diagnosticsApi.js +7 -0
- package/dist/apps/shared/components/calendar/CalendarSearchBox.d.ts +22 -0
- package/dist/apps/shared/components/calendar/CalendarSearchBox.js +24 -0
- package/dist/apps/shared/components/calendar/EventMatchNav.d.ts +17 -0
- package/dist/apps/shared/components/calendar/EventMatchNav.js +37 -0
- package/dist/apps/shared/components/calendar/EventModal.d.ts +17 -1
- package/dist/apps/shared/components/calendar/EventModal.js +13 -11
- package/dist/apps/shared/components/calendar/ListView.d.ts +30 -0
- package/dist/apps/shared/components/calendar/ListView.js +111 -0
- package/dist/apps/shared/components/calendar/MonthView.js +12 -3
- package/dist/apps/shared/components/calendar/SlideIn.d.ts +16 -0
- package/dist/apps/shared/components/calendar/SlideIn.js +32 -0
- package/dist/apps/shared/components/calendar/SplitDayView.js +5 -1
- package/dist/apps/shared/components/calendar/TimeGridView.js +11 -3
- package/dist/apps/shared/components/calendar/activeOccurrence.d.ts +15 -0
- package/dist/apps/shared/components/calendar/activeOccurrence.js +21 -0
- package/dist/apps/shared/components/calendar/allDay.d.ts +4 -0
- package/dist/apps/shared/components/calendar/allDay.js +14 -1
- package/dist/apps/shared/components/calendar/calendarView.d.ts +16 -0
- package/dist/apps/shared/components/calendar/calendarView.js +36 -0
- package/dist/apps/shared/components/layout/AppShell.js +8 -4
- package/dist/apps/shared/components/mail/ConversationList.d.ts +11 -3
- package/dist/apps/shared/components/mail/ConversationList.js +11 -3
- package/dist/apps/shared/components/mail/ConversationThreadPane.js +9 -1
- package/dist/apps/shared/components/mail/MailSelectionBar.js +11 -4
- package/dist/apps/shared/components/mail/MessageDetailPane.js +3 -0
- package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +31 -0
- package/dist/apps/shared/components/mail/compose/ComposeContext.js +123 -11
- package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +6 -1
- package/dist/apps/shared/components/mail/compose/ComposeWindow.js +37 -11
- package/dist/apps/shared/components/mail/compose/ComposeWindowPlaceholder.d.ts +5 -1
- package/dist/apps/shared/components/mail/compose/ComposeWindowPlaceholder.js +10 -6
- package/dist/apps/shared/components/mail/compose/RichTextEditor.js +2 -1
- package/dist/apps/shared/components/mail/compose/quotedBody.d.ts +3 -0
- package/dist/apps/shared/components/mail/compose/quotedBody.js +43 -1
- package/dist/apps/shared/components/mail/labelMenu.d.ts +3 -1
- package/dist/apps/shared/components/mail/labelMenu.js +2 -2
- package/dist/apps/shared/components/mail/layout/MailShell.js +7 -1
- package/dist/apps/shared/components/mail/reading/MessageBody.js +1 -1
- package/dist/apps/shared/components/mail/reading/bodyContent.d.ts +5 -1
- package/dist/apps/shared/components/mail/reading/bodyContent.js +11 -11
- package/dist/apps/shared/components/mail/reading/bodyHtml.d.ts +3 -2
- package/dist/apps/shared/components/mail/reading/bodyHtml.js +8 -4
- package/dist/apps/shared/gestures/useEnterSlide.d.ts +2 -0
- package/dist/apps/shared/gestures/useEnterSlide.js +1 -1
- package/dist/apps/shared/keyboard/keymap.d.ts +12 -0
- package/dist/apps/shared/keyboard/keymap.js +2 -0
- package/dist/apps/shared/mail/rangeSelection.d.ts +20 -0
- package/dist/apps/shared/mail/rangeSelection.js +34 -0
- package/dist/apps/shared/mail/rowExit.d.ts +12 -0
- package/dist/apps/shared/mail/rowExit.js +33 -0
- package/dist/apps/shared/mail/usePermanentDelete.d.ts +2 -0
- package/dist/apps/shared/mail/usePermanentDelete.js +13 -8
- package/dist/apps/www/calendar/index.js +177 -18
- package/dist/apps/www/index.js +257 -93
- package/dist/lib/calendar/eventSearch.d.ts +42 -0
- package/dist/lib/calendar/eventSearch.js +152 -0
- package/dist/lib/components/navigation/BottomTabBar.d.ts +15 -3
- package/dist/lib/components/navigation/BottomTabBar.js +52 -15
- package/dist/lib/components/navigation/NavBadge.d.ts +13 -0
- package/dist/lib/components/navigation/NavBadge.js +18 -0
- package/dist/lib/mail/compose/quotedImages.d.ts +21 -0
- package/dist/lib/mail/compose/quotedImages.js +41 -0
- package/dist/lib/mail/inlineImages.d.ts +38 -0
- package/dist/lib/mail/inlineImages.js +90 -0
- package/dist/lib/mail/mailApi.d.ts +8 -1
- package/dist/lib/mail/mailApi.js +57 -5
- package/lib/calendar/eventSearch.ts +172 -0
- package/lib/components/navigation/BottomTabBar.tsx +107 -22
- package/lib/components/navigation/NavBadge.tsx +33 -0
- package/lib/mail/compose/quotedImages.ts +49 -0
- package/lib/mail/inlineImages.ts +104 -0
- package/lib/mail/mailApi.ts +64 -5
- package/package.json +1 -1
- package/apps/shared/components/admin/diagnostics/VersionsPanel.tsx +0 -36
- package/dist/apps/shared/components/admin/diagnostics/VersionsPanel.d.ts +0 -10
- package/dist/apps/shared/components/admin/diagnostics/VersionsPanel.js +0 -11
package/lib/mail/mailApi.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { ListParams, buildQuery } from "../util/apiQuery.js";
|
|
|
18
18
|
import { deviceTimeZone } from "../util/timeZone.js";
|
|
19
19
|
import type { EncryptionPreference, PublicKey } from "../crypto/keyvaultApi.js";
|
|
20
20
|
import { bytesToBinaryString } from "../crypto/mime.js";
|
|
21
|
+
import { newContentId, parseDataImage } from "./inlineImages.js";
|
|
21
22
|
import type { ResolvedPrincipal } from "./mailboxAccessApi.js";
|
|
22
23
|
|
|
23
24
|
export type { ListParams };
|
|
@@ -1005,6 +1006,8 @@ export interface Attachment {
|
|
|
1005
1006
|
mimeType: string;
|
|
1006
1007
|
sizeBytes: number;
|
|
1007
1008
|
isInline: boolean;
|
|
1009
|
+
/** The part's `Content-ID`, without angle brackets: what an inline image's `cid:` reference names. */
|
|
1010
|
+
contentId?: string;
|
|
1008
1011
|
}
|
|
1009
1012
|
|
|
1010
1013
|
/** Lists the attachments belonging to a single message. */
|
|
@@ -1012,6 +1015,11 @@ export function listAttachments(folderUid: string, messageUid: string, client?:
|
|
|
1012
1015
|
return withClient(client, `/mail/attachments?${buildQuery({ limit: 200 }, { folderUid, messageUid })}`);
|
|
1013
1016
|
}
|
|
1014
1017
|
|
|
1018
|
+
/** Removes an attachment (from a draft). The server re-derives the message's `hasAttachments` itself. */
|
|
1019
|
+
export function deleteAttachment(uid: string, version: number, client?: ApiClient): Promise<void> {
|
|
1020
|
+
return withClient(client, `/mail/attachments/${encodeURIComponent(uid)}?version=${version}`, { method: "DELETE" });
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1015
1023
|
/** The URL to download/display an attachment's binary content — not fetched via `apiFetch`, used directly as
|
|
1016
1024
|
* a link/image `href`/`src`. Honors `configureApiBaseUrl()` (see `apiUrl()`). */
|
|
1017
1025
|
export function attachmentContentUrl(uid: string): string {
|
|
@@ -1023,9 +1031,19 @@ export function attachmentContentUrl(uid: string): string {
|
|
|
1023
1031
|
* always forces `Content-Type: application/json`, which would corrupt binary content; this sends the file's
|
|
1024
1032
|
* own bytes/type directly instead, matching `BaseAttachmentRoute.upload`'s expectation of a raw request body.
|
|
1025
1033
|
*/
|
|
1026
|
-
export async function uploadAttachment(messageUid: string, file: File): Promise<Attachment> {
|
|
1027
|
-
|
|
1028
|
-
const
|
|
1034
|
+
export async function uploadAttachment(messageUid: string, file: File, options: { inline?: boolean; contentId?: string } = {}): Promise<Attachment> {
|
|
1035
|
+
// Percent-encoded, not form-encoded (`URLSearchParams` writes a space as `+`, which the server reads as a plus sign: "My+photo.png").
|
|
1036
|
+
const query: Record<string, string> = { messageUid, filename: file.name, mimeType: file.type || "application/octet-stream" };
|
|
1037
|
+
if (options.inline) {
|
|
1038
|
+
// An image shown in the text of the message: it goes out as an inline part, which the text refers to by this `Content-ID`
|
|
1039
|
+
// (`BaseMailComposeRoute.rewriteInlineImageSources()` turns the editor's preview URL into that `cid:` reference).
|
|
1040
|
+
query.isInline = "true";
|
|
1041
|
+
query.contentId = options.contentId ?? newContentId();
|
|
1042
|
+
}
|
|
1043
|
+
const params = Object.entries(query)
|
|
1044
|
+
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
|
1045
|
+
.join("&");
|
|
1046
|
+
const res = await fetch(apiUrl(`/mail/attachments/upload?${params}`), {
|
|
1029
1047
|
method: "POST",
|
|
1030
1048
|
credentials: "include",
|
|
1031
1049
|
headers: withCsrfHeader({ "Content-Type": file.type || "application/octet-stream" }),
|
|
@@ -1130,13 +1148,54 @@ export function emptyFolder(folderUid: string, client?: ApiClient): Promise<void
|
|
|
1130
1148
|
* — see `BaseMailComposeRoute` (this app's own compose-assembly glue, since `@rapidmx/restapi`'s `send()`
|
|
1131
1149
|
* itself does no MIME composition). Does not send the message.
|
|
1132
1150
|
*/
|
|
1133
|
-
export function assembleDraft(messageUid: string, input: AssembleDraftInput, client?: ApiClient): Promise<Message> {
|
|
1151
|
+
export async function assembleDraft(messageUid: string, input: AssembleDraftInput, client?: ApiClient): Promise<Message> {
|
|
1152
|
+
const html = await attachDataImages(messageUid, input.html);
|
|
1134
1153
|
return withClient(client, `/mail/compose/${encodeURIComponent(messageUid)}/assemble`, {
|
|
1135
1154
|
method: "POST",
|
|
1136
|
-
body: JSON.stringify(input),
|
|
1155
|
+
body: JSON.stringify({ ...input, html }),
|
|
1137
1156
|
});
|
|
1138
1157
|
}
|
|
1139
1158
|
|
|
1159
|
+
/** `data:` images already attached to a draft: its uid and the image, to the URL of the attachment it became. */
|
|
1160
|
+
const attachedDataImages = new Map<string, string>();
|
|
1161
|
+
|
|
1162
|
+
const DATA_IMAGE_TAG = /(<img\b[^>]*?\bsrc\s*=\s*)(["'])(data:image\/[^"']*)\2/gi;
|
|
1163
|
+
|
|
1164
|
+
/** Names a picture by its type, for the attachment it becomes. */
|
|
1165
|
+
function pictureName(contentType: string): string {
|
|
1166
|
+
return `image.${contentType.split("/")[1].replace(/\+.*/, "").replace("jpeg", "jpg")}`;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
/**
|
|
1170
|
+
* `html` with each `<img>` that embeds its picture as a `data:` URI (a quoted original's image, one pasted into the editor) pointed at an
|
|
1171
|
+
* attachment of the draft instead: the server drops `data:` images from the message it composes, and an attachment is what it makes an
|
|
1172
|
+
* inline part of. A picture is attached once per draft however often the draft is saved.
|
|
1173
|
+
*/
|
|
1174
|
+
async function attachDataImages(messageUid: string, html: string): Promise<string> {
|
|
1175
|
+
const found = Array.from(html.matchAll(DATA_IMAGE_TAG));
|
|
1176
|
+
if (found.length === 0) {
|
|
1177
|
+
return html;
|
|
1178
|
+
}
|
|
1179
|
+
const urls = new Map<string, string>();
|
|
1180
|
+
for (const [, , , uri] of found) {
|
|
1181
|
+
const key = `${messageUid}\n${uri}`;
|
|
1182
|
+
const known = attachedDataImages.get(key);
|
|
1183
|
+
if (known) {
|
|
1184
|
+
urls.set(uri, known);
|
|
1185
|
+
continue;
|
|
1186
|
+
}
|
|
1187
|
+
const image = parseDataImage(uri);
|
|
1188
|
+
if (!image) {
|
|
1189
|
+
continue;
|
|
1190
|
+
}
|
|
1191
|
+
const attachment = await uploadAttachment(messageUid, new File([image.bytes as BlobPart], pictureName(image.contentType), { type: image.contentType }), { inline: true });
|
|
1192
|
+
const url = attachmentContentUrl(attachment.uid);
|
|
1193
|
+
attachedDataImages.set(key, url);
|
|
1194
|
+
urls.set(uri, url);
|
|
1195
|
+
}
|
|
1196
|
+
return html.replace(DATA_IMAGE_TAG, (match, start: string, quote: string, uri: string) => (urls.has(uri) ? `${start}${quote}${urls.get(uri)}${quote}` : match));
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1140
1199
|
export interface AssembleDraftRawInput {
|
|
1141
1200
|
to: ComposeRecipientInput[];
|
|
1142
1201
|
cc?: ComposeRecipientInput[];
|
package/package.json
CHANGED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
-
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
-
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
-
import React from "react";
|
|
6
|
-
import Alert from "../../../../../lib/components/feedback/Alert.js";
|
|
7
|
-
import type { DiagnosticsVersions } from "./diagnosticsApi.js";
|
|
8
|
-
import type { DiagnosticsResource } from "./useDiagnosticsResource.js";
|
|
9
|
-
import ComponentsTable from "./ComponentsTable.js";
|
|
10
|
-
import InstalledPlugins, { InstalledPluginsData } from "./InstalledPlugins.js";
|
|
11
|
-
import PackagesTable from "./PackagesTable.js";
|
|
12
|
-
import ServerVersionCard from "./ServerVersionCard.js";
|
|
13
|
-
|
|
14
|
-
export interface VersionsPanelProps {
|
|
15
|
-
versions: DiagnosticsResource<DiagnosticsVersions>;
|
|
16
|
-
plugins: DiagnosticsResource<InstalledPluginsData>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** The Versions tab: the server, its packages, the installed plugins and the install's other containers. */
|
|
20
|
-
export default function VersionsPanel({ versions, plugins }: VersionsPanelProps) {
|
|
21
|
-
const { data, error, loading } = versions;
|
|
22
|
-
return (
|
|
23
|
-
<div className="space-y-6">
|
|
24
|
-
{error && <Alert>{error}</Alert>}
|
|
25
|
-
{!data && loading && <p className="text-sm text-text-muted">Loading…</p>}
|
|
26
|
-
{data && (
|
|
27
|
-
<>
|
|
28
|
-
<ServerVersionCard server={data.server} />
|
|
29
|
-
<ComponentsTable components={data.components ?? []} kubernetes={data.kubernetes ?? { available: false }} />
|
|
30
|
-
<InstalledPlugins data={plugins.data} error={plugins.error} loading={plugins.loading} />
|
|
31
|
-
<PackagesTable packages={data.packages ?? []} />
|
|
32
|
-
</>
|
|
33
|
-
)}
|
|
34
|
-
</div>
|
|
35
|
-
);
|
|
36
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { DiagnosticsVersions } from "./diagnosticsApi.js";
|
|
3
|
-
import type { DiagnosticsResource } from "./useDiagnosticsResource.js";
|
|
4
|
-
import { InstalledPluginsData } from "./InstalledPlugins.js";
|
|
5
|
-
export interface VersionsPanelProps {
|
|
6
|
-
versions: DiagnosticsResource<DiagnosticsVersions>;
|
|
7
|
-
plugins: DiagnosticsResource<InstalledPluginsData>;
|
|
8
|
-
}
|
|
9
|
-
/** The Versions tab: the server, its packages, the installed plugins and the install's other containers. */
|
|
10
|
-
export default function VersionsPanel({ versions, plugins }: VersionsPanelProps): React.JSX.Element;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import Alert from "../../../../../lib/components/feedback/Alert.js";
|
|
3
|
-
import ComponentsTable from "./ComponentsTable.js";
|
|
4
|
-
import InstalledPlugins from "./InstalledPlugins.js";
|
|
5
|
-
import PackagesTable from "./PackagesTable.js";
|
|
6
|
-
import ServerVersionCard from "./ServerVersionCard.js";
|
|
7
|
-
/** The Versions tab: the server, its packages, the installed plugins and the install's other containers. */
|
|
8
|
-
export default function VersionsPanel({ versions, plugins }) {
|
|
9
|
-
const { data, error, loading } = versions;
|
|
10
|
-
return (_jsxs("div", { className: "space-y-6", children: [error && _jsx(Alert, { children: error }), !data && loading && _jsx("p", { className: "text-sm text-text-muted", children: "Loading\u2026" }), data && (_jsxs(_Fragment, { children: [_jsx(ServerVersionCard, { server: data.server }), _jsx(ComponentsTable, { components: data.components ?? [], kubernetes: data.kubernetes ?? { available: false } }), _jsx(InstalledPlugins, { data: plugins.data, error: plugins.error, loading: plugins.loading }), _jsx(PackagesTable, { packages: data.packages ?? [] })] }))] }));
|
|
11
|
-
}
|