@arbidocs/blocks 0.4.106 → 0.4.108
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/bin/arbidocs-render-take.mjs +27 -0
- package/dist/NativeDocxEditor-UAZUKZ77.js +10 -0
- package/dist/NativeDocxEditor-UAZUKZ77.js.map +1 -0
- package/dist/NativeDocxEditor-YX7B7OFH.cjs +31 -0
- package/dist/NativeDocxEditor-YX7B7OFH.cjs.map +1 -0
- package/dist/{chunk-W2RTZOK3.js → chunk-A2MN2ZLX.js} +1750 -1779
- package/dist/chunk-A2MN2ZLX.js.map +1 -0
- package/dist/{chunk-3R6XBYL7.cjs → chunk-DTBSGG36.cjs} +7 -2
- package/dist/chunk-DTBSGG36.cjs.map +1 -0
- package/dist/{chunk-4GFB5U3K.js → chunk-EGDWNEAG.js} +4 -3
- package/dist/chunk-EGDWNEAG.js.map +1 -0
- package/dist/chunk-GYAUJ4KT.js +71 -0
- package/dist/chunk-GYAUJ4KT.js.map +1 -0
- package/dist/{chunk-PIT2YZCK.js → chunk-JQVPGMLU.js} +3 -3
- package/dist/{chunk-PIT2YZCK.js.map → chunk-JQVPGMLU.js.map} +1 -1
- package/dist/{chunk-LGX6UFYG.js → chunk-P2KPDPFF.js} +8 -3
- package/dist/chunk-P2KPDPFF.js.map +1 -0
- package/dist/{chunk-ZWWN4CUL.cjs → chunk-QT6EGMAJ.cjs} +1748 -1778
- package/dist/chunk-QT6EGMAJ.cjs.map +1 -0
- package/dist/chunk-S24XEVPS.cjs +73 -0
- package/dist/chunk-S24XEVPS.cjs.map +1 -0
- package/dist/{chunk-TP3FAP5J.cjs → chunk-TTXK62YI.cjs} +5 -5
- package/dist/{chunk-TP3FAP5J.cjs.map → chunk-TTXK62YI.cjs.map} +1 -1
- package/dist/{chunk-7LLLQUM7.cjs → chunk-ZYSY4L5L.cjs} +6 -5
- package/dist/chunk-ZYSY4L5L.cjs.map +1 -0
- package/dist/collaboration/index.cjs +15 -15
- package/dist/collaboration/index.js +1 -1
- package/dist/collaboration/mail/MailMessageView.d.ts +3 -1
- package/dist/connect/docx.cjs +7 -6
- package/dist/connect/docx.cjs.map +1 -1
- package/dist/connect/docx.js +5 -4
- package/dist/connect/docx.js.map +1 -1
- package/dist/connect/index.cjs +368 -52
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +356 -41
- package/dist/connect/index.js.map +1 -1
- package/dist/connection/mail/ConnectedMailComposer.d.ts +12 -2
- package/dist/connection/mail/ConnectedMailMessage.d.ts +19 -0
- package/dist/connection/mail/ConnectedMailbox.d.ts +7 -3
- package/dist/connection/mail/MailComposerForm.d.ts +12 -2
- package/dist/connection/mail/index.d.ts +2 -1
- package/dist/connection/mail/types.d.ts +15 -0
- package/dist/connection/mail/useWordBody.d.ts +48 -0
- package/dist/docx/NativeDocxEditor.d.ts +9 -1
- package/dist/docx/index.cjs +51 -50
- package/dist/docx/index.cjs.map +1 -1
- package/dist/docx/index.js +4 -3
- package/dist/docx/index.js.map +1 -1
- package/dist/docx/template/HouseTemplate.d.ts +5 -0
- package/dist/index.cjs +15 -15
- package/dist/index.js +1 -1
- package/dist/record/index.cjs +307 -66
- package/dist/record/index.cjs.map +1 -1
- package/dist/record/index.d.ts +145 -26
- package/dist/record/index.js +301 -67
- package/dist/record/index.js.map +1 -1
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +8 -5
- package/record/render-overlays.mjs +152 -0
- package/record/render-take.py +985 -0
- package/src/docx/styles.css +22 -0
- package/dist/chunk-3R6XBYL7.cjs.map +0 -1
- package/dist/chunk-4GFB5U3K.js.map +0 -1
- package/dist/chunk-7LLLQUM7.cjs.map +0 -1
- package/dist/chunk-LGX6UFYG.js.map +0 -1
- package/dist/chunk-W2RTZOK3.js.map +0 -1
- package/dist/chunk-ZWWN4CUL.cjs.map +0 -1
package/dist/connect/index.cjs
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
var chunk5YXG342J_cjs = require('../chunk-5YXG342J.cjs');
|
|
5
5
|
var chunkXMBYDLZQ_cjs = require('../chunk-XMBYDLZQ.cjs');
|
|
6
|
-
var
|
|
6
|
+
var chunkZYSY4L5L_cjs = require('../chunk-ZYSY4L5L.cjs');
|
|
7
7
|
var chunkMUMH3Z6K_cjs = require('../chunk-MUMH3Z6K.cjs');
|
|
8
8
|
var chunkJH6JTI76_cjs = require('../chunk-JH6JTI76.cjs');
|
|
9
|
-
require('../chunk-
|
|
9
|
+
require('../chunk-S24XEVPS.cjs');
|
|
10
|
+
require('../chunk-QT6EGMAJ.cjs');
|
|
10
11
|
require('../chunk-5FYU7ZIU.cjs');
|
|
11
12
|
var chunkO4YPVYPO_cjs = require('../chunk-O4YPVYPO.cjs');
|
|
12
13
|
var chunkSKSE4OT6_cjs = require('../chunk-SKSE4OT6.cjs');
|
|
@@ -27,7 +28,7 @@ require('../chunk-B4SRYJLM.cjs');
|
|
|
27
28
|
require('../chunk-7UTB4PHM.cjs');
|
|
28
29
|
require('../chunk-PPCATBOY.cjs');
|
|
29
30
|
var chunkKDG6FER6_cjs = require('../chunk-KDG6FER6.cjs');
|
|
30
|
-
var
|
|
31
|
+
var chunkDTBSGG36_cjs = require('../chunk-DTBSGG36.cjs');
|
|
31
32
|
var chunkULWRNGGE_cjs = require('../chunk-ULWRNGGE.cjs');
|
|
32
33
|
require('../chunk-IXALYQT7.cjs');
|
|
33
34
|
require('../chunk-FX3K6LNZ.cjs');
|
|
@@ -43,6 +44,7 @@ var lucideReact = require('lucide-react');
|
|
|
43
44
|
var documentTools = require('@arbidocs/react/document-tools');
|
|
44
45
|
var shell = require('@arbidocs/react/shell');
|
|
45
46
|
var client = require('@arbidocs/client');
|
|
47
|
+
var reactDom = require('react-dom');
|
|
46
48
|
|
|
47
49
|
function ConnectionBoundWebSocket({ children }) {
|
|
48
50
|
const { status } = chunkMUMH3Z6K_cjs.useConnection();
|
|
@@ -664,7 +666,7 @@ function WorkflowWordDialog({
|
|
|
664
666
|
title: title ?? labels.wordTitle,
|
|
665
667
|
size: "xl",
|
|
666
668
|
testId: "workflow-word-dialog",
|
|
667
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(chunkULWRNGGE_cjs.ModalScaffold.Body, { className: "h-[70dvh] p-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
669
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(chunkULWRNGGE_cjs.ModalScaffold.Body, { className: "h-[70dvh] p-0", children: /* @__PURE__ */ jsxRuntime.jsx(chunkZYSY4L5L_cjs.ConnectedNativeDocxEditor, { documentId: id, title: title ?? labels.wordTitle }) })
|
|
668
670
|
}
|
|
669
671
|
);
|
|
670
672
|
}
|
|
@@ -2063,11 +2065,96 @@ function ConnectedMailAccounts({
|
|
|
2063
2065
|
}
|
|
2064
2066
|
);
|
|
2065
2067
|
}
|
|
2068
|
+
var sessionRooms = /* @__PURE__ */ new Map();
|
|
2069
|
+
function useWordBody({
|
|
2070
|
+
word,
|
|
2071
|
+
client,
|
|
2072
|
+
initial,
|
|
2073
|
+
sessionKey,
|
|
2074
|
+
roomId: givenRoomId,
|
|
2075
|
+
onBodyChange
|
|
2076
|
+
}) {
|
|
2077
|
+
const [documentKey] = react.useState(
|
|
2078
|
+
() => `mail-${sessionKey ?? initial.draft_id ?? crypto.randomUUID()}`
|
|
2079
|
+
);
|
|
2080
|
+
const roomRef = react.useRef(sessionRooms.get(documentKey) ?? givenRoomId);
|
|
2081
|
+
const [roomId, setRoomId] = react.useState(roomRef.current);
|
|
2082
|
+
const [project, setProject] = react.useState();
|
|
2083
|
+
const stateRef = react.useRef(null);
|
|
2084
|
+
const changed = react.useRef(onBodyChange);
|
|
2085
|
+
react.useEffect(() => {
|
|
2086
|
+
changed.current = onBodyChange;
|
|
2087
|
+
});
|
|
2088
|
+
const opening = react.useRef(null);
|
|
2089
|
+
const adapter = react.useMemo(
|
|
2090
|
+
() => ({
|
|
2091
|
+
...word.adapter,
|
|
2092
|
+
open: async () => {
|
|
2093
|
+
if (!roomRef.current && opening.current) return opening.current;
|
|
2094
|
+
const request = client.openDraftEditor(
|
|
2095
|
+
roomRef.current ? { roomId: roomRef.current } : { draftId: initial.draft_id ?? void 0, text: initial.text, html: initial.html }
|
|
2096
|
+
);
|
|
2097
|
+
if (!roomRef.current) opening.current = request;
|
|
2098
|
+
try {
|
|
2099
|
+
const session = await request;
|
|
2100
|
+
roomRef.current = session.room_id;
|
|
2101
|
+
sessionRooms.set(documentKey, session.room_id);
|
|
2102
|
+
setRoomId(session.room_id);
|
|
2103
|
+
setProject(session.project ?? null);
|
|
2104
|
+
return session;
|
|
2105
|
+
} finally {
|
|
2106
|
+
opening.current = null;
|
|
2107
|
+
}
|
|
2108
|
+
},
|
|
2109
|
+
save: async () => {
|
|
2110
|
+
throw new Error("Save the draft from the composer");
|
|
2111
|
+
},
|
|
2112
|
+
onDirtyChange: (dirty) => {
|
|
2113
|
+
if (dirty) changed.current();
|
|
2114
|
+
}
|
|
2115
|
+
}),
|
|
2116
|
+
// The editor keeps its adapter for the session; the seed matters only when it first opens.
|
|
2117
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2118
|
+
[word.adapter, client, documentKey]
|
|
2119
|
+
);
|
|
2120
|
+
react.useEffect(() => {
|
|
2121
|
+
if (!roomId) return;
|
|
2122
|
+
return word.onRoomOpened?.(roomId) || void 0;
|
|
2123
|
+
}, [roomId, word]);
|
|
2124
|
+
const editor = react$1.useMailDraftEditor();
|
|
2125
|
+
const state = () => stateRef.current?.() ?? null;
|
|
2126
|
+
return {
|
|
2127
|
+
adapter,
|
|
2128
|
+
documentKey,
|
|
2129
|
+
stateRef,
|
|
2130
|
+
ready: !!roomId,
|
|
2131
|
+
save: (compose) => editor.save(roomRef.current, compose, state()),
|
|
2132
|
+
send: async (compose) => {
|
|
2133
|
+
const result = await editor.send(roomRef.current, compose, state());
|
|
2134
|
+
sessionRooms.delete(documentKey);
|
|
2135
|
+
return result;
|
|
2136
|
+
},
|
|
2137
|
+
body: (final) => editor.body(roomRef.current, final, state()),
|
|
2138
|
+
project,
|
|
2139
|
+
chooseProject: async (projectExtId) => {
|
|
2140
|
+
setProject(await editor.setProject(roomRef.current, projectExtId));
|
|
2141
|
+
}
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2066
2144
|
var MailBodyEditor = react.lazy(
|
|
2067
2145
|
() => import('../MailBodyEditor-D7MGJMLH.cjs').catch(() => ({
|
|
2068
|
-
default:
|
|
2146
|
+
default: chunkDTBSGG36_cjs.PlainMailBodyEditor
|
|
2069
2147
|
}))
|
|
2070
2148
|
);
|
|
2149
|
+
var NativeDocxEditor = react.lazy(
|
|
2150
|
+
() => import('../NativeDocxEditor-YX7B7OFH.cjs').then((m) => ({ default: m.NativeDocxEditor }))
|
|
2151
|
+
);
|
|
2152
|
+
var NO_WORD = {
|
|
2153
|
+
adapter: {
|
|
2154
|
+
request: () => Promise.reject(new Error("No Word editor")),
|
|
2155
|
+
loadFonts: () => Promise.reject(new Error("No Word editor"))
|
|
2156
|
+
}
|
|
2157
|
+
};
|
|
2071
2158
|
function MailComposerForm({
|
|
2072
2159
|
account,
|
|
2073
2160
|
initial,
|
|
@@ -2076,13 +2163,18 @@ function MailComposerForm({
|
|
|
2076
2163
|
drafts,
|
|
2077
2164
|
onClose,
|
|
2078
2165
|
onOpenDraft,
|
|
2166
|
+
onReload,
|
|
2079
2167
|
onChange,
|
|
2080
2168
|
embedded = false,
|
|
2081
2169
|
closeRequestRef,
|
|
2082
2170
|
localDraftId: initialLocalDraftId,
|
|
2083
2171
|
offline,
|
|
2084
2172
|
documents,
|
|
2085
|
-
notify: notify3
|
|
2173
|
+
notify: notify3,
|
|
2174
|
+
word,
|
|
2175
|
+
sessionKey,
|
|
2176
|
+
roomId,
|
|
2177
|
+
headerSlot
|
|
2086
2178
|
}) {
|
|
2087
2179
|
const { client } = react$1.useMailClient();
|
|
2088
2180
|
const [to, setTo] = react.useState(initial.to.map((r) => r.email).join("; "));
|
|
@@ -2099,7 +2191,26 @@ function MailComposerForm({
|
|
|
2099
2191
|
const [dirty, setDirty] = react.useState(false);
|
|
2100
2192
|
const [attaching, setAttaching] = react.useState(false);
|
|
2101
2193
|
const [saved, setSaved] = react.useState(false);
|
|
2194
|
+
const [replacedBy, setReplacedBy] = react.useState();
|
|
2102
2195
|
const isOnline = react$1.useMailOnline();
|
|
2196
|
+
const [usesWord] = react.useState(
|
|
2197
|
+
() => !!word && !!client.openDraftEditor && account?.provider === "native" && isOnline && !initialLocalDraftId
|
|
2198
|
+
);
|
|
2199
|
+
const [bodyChanged, setBodyChanged] = react.useState(false);
|
|
2200
|
+
const [wordPending, setWordPending] = react.useState(false);
|
|
2201
|
+
const projects = react$1.useMailProjects({ enabled: usesWord });
|
|
2202
|
+
const wordBody = useWordBody({
|
|
2203
|
+
word: word ?? NO_WORD,
|
|
2204
|
+
client,
|
|
2205
|
+
initial,
|
|
2206
|
+
sessionKey,
|
|
2207
|
+
roomId,
|
|
2208
|
+
onBodyChange: () => {
|
|
2209
|
+
setBodyChanged(true);
|
|
2210
|
+
setSaved(false);
|
|
2211
|
+
setDirty(true);
|
|
2212
|
+
}
|
|
2213
|
+
});
|
|
2103
2214
|
const [localDraftId, setLocalDraftId] = react.useState(initialLocalDraftId);
|
|
2104
2215
|
const [savedLocally, setSavedLocally] = react.useState(false);
|
|
2105
2216
|
const [secure, setSecure] = react.useState(initial.secure_delivery ?? false);
|
|
@@ -2113,9 +2224,9 @@ function MailComposerForm({
|
|
|
2113
2224
|
}, [drafts, draftId, subject]);
|
|
2114
2225
|
const body = () => ({
|
|
2115
2226
|
...initial,
|
|
2116
|
-
to:
|
|
2117
|
-
cc:
|
|
2118
|
-
bcc:
|
|
2227
|
+
to: chunkDTBSGG36_cjs.parseMailRecipients(to),
|
|
2228
|
+
cc: chunkDTBSGG36_cjs.parseMailRecipients(cc),
|
|
2229
|
+
bcc: chunkDTBSGG36_cjs.parseMailRecipients(bcc),
|
|
2119
2230
|
subject,
|
|
2120
2231
|
text,
|
|
2121
2232
|
html,
|
|
@@ -2143,27 +2254,46 @@ function MailComposerForm({
|
|
|
2143
2254
|
const send = react$1.useSendMail(
|
|
2144
2255
|
offline && { keep: queueInOutbox, isNetworkFailure: offline.isNetworkFailure }
|
|
2145
2256
|
);
|
|
2146
|
-
const
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
if ("onDevice" in result) {
|
|
2153
|
-
setSavedLocally(true);
|
|
2154
|
-
return;
|
|
2155
|
-
}
|
|
2156
|
-
setSavedLocally(false);
|
|
2157
|
-
setDraftId(result.id);
|
|
2158
|
-
if (localDraftId) {
|
|
2159
|
-
void offline?.deleteDraft(localDraftId);
|
|
2160
|
-
setLocalDraftId(void 0);
|
|
2161
|
-
}
|
|
2162
|
-
},
|
|
2163
|
-
onError: (err) => setError(err.message)
|
|
2257
|
+
const onSaved = (result) => {
|
|
2258
|
+
setSaved(true);
|
|
2259
|
+
setDirty(false);
|
|
2260
|
+
if ("onDevice" in result) {
|
|
2261
|
+
setSavedLocally(true);
|
|
2262
|
+
return;
|
|
2164
2263
|
}
|
|
2165
|
-
|
|
2166
|
-
|
|
2264
|
+
setSavedLocally(false);
|
|
2265
|
+
setDraftId(result.id);
|
|
2266
|
+
setReplacedBy(void 0);
|
|
2267
|
+
if (localDraftId) {
|
|
2268
|
+
void offline?.deleteDraft(localDraftId);
|
|
2269
|
+
setLocalDraftId(void 0);
|
|
2270
|
+
}
|
|
2271
|
+
};
|
|
2272
|
+
const saveDraft = () => {
|
|
2273
|
+
if (usesWord) {
|
|
2274
|
+
if (!wordBody.ready) return setError("The editor is still opening");
|
|
2275
|
+
setWordPending(true);
|
|
2276
|
+
void wordBody.save(body()).then(
|
|
2277
|
+
(result) => {
|
|
2278
|
+
onSaved(result);
|
|
2279
|
+
setBodyChanged(false);
|
|
2280
|
+
},
|
|
2281
|
+
(err) => setError(err.message)
|
|
2282
|
+
).finally(() => setWordPending(false));
|
|
2283
|
+
return;
|
|
2284
|
+
}
|
|
2285
|
+
save.mutate(
|
|
2286
|
+
{ accountId: account.id, compose: body() },
|
|
2287
|
+
{ onSuccess: onSaved, onError: (err) => setError(err.message) }
|
|
2288
|
+
);
|
|
2289
|
+
};
|
|
2290
|
+
react$1.useMailDraftReplaced(draftId, (newId) => {
|
|
2291
|
+
if (save.isPending || wordPending) return;
|
|
2292
|
+
setDraftId(newId);
|
|
2293
|
+
if (!dirty && onReload) onReload(newId);
|
|
2294
|
+
else setReplacedBy(newId);
|
|
2295
|
+
});
|
|
2296
|
+
const sendMessage = async () => {
|
|
2167
2297
|
let value = attemptedPayload.current;
|
|
2168
2298
|
if (value === null) {
|
|
2169
2299
|
value = body();
|
|
@@ -2172,18 +2302,41 @@ function MailComposerForm({
|
|
|
2172
2302
|
if (problem) return setError(problem);
|
|
2173
2303
|
if (!(offline && !isOnline)) attemptedPayload.current = value;
|
|
2174
2304
|
}
|
|
2305
|
+
if (usesWord) {
|
|
2306
|
+
if (!wordBody.ready) return setError("The editor is still opening");
|
|
2307
|
+
const refused = (err) => {
|
|
2308
|
+
setError(err.message);
|
|
2309
|
+
if (err.status === 409) attemptedPayload.current = null;
|
|
2310
|
+
};
|
|
2311
|
+
setWordPending(true);
|
|
2312
|
+
try {
|
|
2313
|
+
if (!secure) {
|
|
2314
|
+
await wordBody.send({ ...value, request_id: requestId.current });
|
|
2315
|
+
notify3("Email queued for delivery", "success");
|
|
2316
|
+
onClose();
|
|
2317
|
+
return;
|
|
2318
|
+
}
|
|
2319
|
+
value = { ...value, ...await wordBody.body(true) };
|
|
2320
|
+
attemptedPayload.current = value;
|
|
2321
|
+
} catch (err) {
|
|
2322
|
+
return refused(err);
|
|
2323
|
+
} finally {
|
|
2324
|
+
setWordPending(false);
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2175
2327
|
const sending = account;
|
|
2328
|
+
const message = value;
|
|
2176
2329
|
send.mutate(
|
|
2177
2330
|
{
|
|
2178
2331
|
accountId: account.id,
|
|
2179
|
-
compose:
|
|
2332
|
+
compose: message,
|
|
2180
2333
|
requestId: requestId.current,
|
|
2181
2334
|
// Secure delivery prepares its encrypted payload once.
|
|
2182
2335
|
secure: secure ? async () => {
|
|
2183
2336
|
if (sending?.provider !== "native" || !client.prepareSecureMail)
|
|
2184
2337
|
throw new Error("Choose your native inbox to send securely");
|
|
2185
2338
|
securePayload.current ??= await client.prepareSecureMail(
|
|
2186
|
-
|
|
2339
|
+
message,
|
|
2187
2340
|
sending,
|
|
2188
2341
|
requestId.current
|
|
2189
2342
|
);
|
|
@@ -2207,7 +2360,7 @@ function MailComposerForm({
|
|
|
2207
2360
|
}
|
|
2208
2361
|
);
|
|
2209
2362
|
};
|
|
2210
|
-
const busy = attaching || save.isPending || send.isPending;
|
|
2363
|
+
const busy = attaching || save.isPending || send.isPending || wordPending;
|
|
2211
2364
|
const locked = busy || attemptedPayload.current !== null;
|
|
2212
2365
|
const addFiles = async (files) => {
|
|
2213
2366
|
if (!files) return;
|
|
@@ -2246,7 +2399,7 @@ function MailComposerForm({
|
|
|
2246
2399
|
};
|
|
2247
2400
|
const close = () => {
|
|
2248
2401
|
if (busy) return;
|
|
2249
|
-
if (!saved && (dirty || !draftId) && (text || subject || to || cc || bcc || attachments.length) && !window.confirm("Close this message without saving your latest changes?"))
|
|
2402
|
+
if (!saved && (dirty || !draftId) && (text || subject || to || cc || bcc || attachments.length || bodyChanged) && !window.confirm("Close this message without saving your latest changes?"))
|
|
2250
2403
|
return;
|
|
2251
2404
|
onClose();
|
|
2252
2405
|
};
|
|
@@ -2256,6 +2409,30 @@ function MailComposerForm({
|
|
|
2256
2409
|
react.useEffect(() => {
|
|
2257
2410
|
onChange?.(body());
|
|
2258
2411
|
}, [to, cc, bcc, subject, text, html, attachments, draftId, secure]);
|
|
2412
|
+
const billTo = wordBody.project && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2413
|
+
"label",
|
|
2414
|
+
{
|
|
2415
|
+
className: "flex items-center gap-1 text-xs text-muted-foreground",
|
|
2416
|
+
title: "ARBI's work on this email is billed to this project",
|
|
2417
|
+
children: [
|
|
2418
|
+
"Billed to",
|
|
2419
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2420
|
+
"select",
|
|
2421
|
+
{
|
|
2422
|
+
"aria-label": "Bill to",
|
|
2423
|
+
className: "max-w-[12rem] truncate rounded bg-transparent py-0.5 text-foreground hover:bg-muted/60 focus:bg-muted/60 focus:outline-none",
|
|
2424
|
+
value: wordBody.project.external_id,
|
|
2425
|
+
disabled: busy,
|
|
2426
|
+
onChange: (e) => {
|
|
2427
|
+
const chosen = projects.data?.find((p) => p.external_id === e.target.value);
|
|
2428
|
+
void wordBody.chooseProject(chosen && !chosen.personal ? chosen.external_id : null).catch((err) => setError(err.message));
|
|
2429
|
+
},
|
|
2430
|
+
children: (projects.data ?? [wordBody.project]).map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.external_id, children: p.personal ? `${p.name} (personal)` : p.name }, p.external_id))
|
|
2431
|
+
}
|
|
2432
|
+
)
|
|
2433
|
+
]
|
|
2434
|
+
}
|
|
2435
|
+
);
|
|
2259
2436
|
const form = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2260
2437
|
"form",
|
|
2261
2438
|
{
|
|
@@ -2271,7 +2448,7 @@ function MailComposerForm({
|
|
|
2271
2448
|
onSubmit: (e) => {
|
|
2272
2449
|
e.preventDefault();
|
|
2273
2450
|
setError("");
|
|
2274
|
-
sendMessage();
|
|
2451
|
+
void sendMessage();
|
|
2275
2452
|
},
|
|
2276
2453
|
className: embedded ? "flex h-full min-h-0 w-full flex-col bg-background" : "flex max-h-[95dvh] w-full max-w-3xl flex-col rounded-xl border bg-background shadow-2xl",
|
|
2277
2454
|
children: [
|
|
@@ -2289,7 +2466,7 @@ function MailComposerForm({
|
|
|
2289
2466
|
}
|
|
2290
2467
|
)
|
|
2291
2468
|
] }),
|
|
2292
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-0 flex-1 overflow-auto px-5 py-3", children: [
|
|
2469
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 flex-col overflow-auto px-5 py-3", children: [
|
|
2293
2470
|
sameSubjectDraft && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2294
2471
|
"div",
|
|
2295
2472
|
{
|
|
@@ -2310,10 +2487,36 @@ function MailComposerForm({
|
|
|
2310
2487
|
]
|
|
2311
2488
|
}
|
|
2312
2489
|
),
|
|
2490
|
+
replacedBy && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2491
|
+
"div",
|
|
2492
|
+
{
|
|
2493
|
+
role: "status",
|
|
2494
|
+
className: "mb-3 flex items-center justify-between gap-3 rounded-md bg-muted/40 px-3 py-2 text-xs text-muted-foreground",
|
|
2495
|
+
children: [
|
|
2496
|
+
"This draft was changed elsewhere (by ARBI or in another tab). Saving keeps your version.",
|
|
2497
|
+
onReload && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2498
|
+
ui.Button,
|
|
2499
|
+
{
|
|
2500
|
+
type: "button",
|
|
2501
|
+
variant: "ghost",
|
|
2502
|
+
className: "h-7 shrink-0 text-xs",
|
|
2503
|
+
disabled: busy,
|
|
2504
|
+
onClick: () => {
|
|
2505
|
+
if (window.confirm("Discard your unsaved changes and load the changed draft?"))
|
|
2506
|
+
onReload(replacedBy);
|
|
2507
|
+
},
|
|
2508
|
+
children: "Load changes"
|
|
2509
|
+
}
|
|
2510
|
+
)
|
|
2511
|
+
]
|
|
2512
|
+
}
|
|
2513
|
+
),
|
|
2313
2514
|
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mb-2 flex items-center gap-3 border-b border-border/60 pb-3 text-xs text-muted-foreground", children: [
|
|
2314
2515
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-14 shrink-0", children: "From" }),
|
|
2315
2516
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-muted/50 px-2 py-1 text-foreground", children: account?.email ?? "Connect a mailbox to send" })
|
|
2316
2517
|
] }),
|
|
2518
|
+
usesWord && wordBody.project && !headerSlot && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2", children: billTo }),
|
|
2519
|
+
usesWord && wordBody.project && headerSlot && reactDom.createPortal(billTo, headerSlot),
|
|
2317
2520
|
[
|
|
2318
2521
|
["To", to, setTo],
|
|
2319
2522
|
["Cc", cc, setCc],
|
|
@@ -2386,7 +2589,24 @@ function MailComposerForm({
|
|
|
2386
2589
|
}
|
|
2387
2590
|
)
|
|
2388
2591
|
] }),
|
|
2389
|
-
/* @__PURE__ */ jsxRuntime.jsx(react.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "py-4 text-sm text-muted-foreground", children: "Loading editor\u2026" }), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2592
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "py-4 text-sm text-muted-foreground", children: "Loading editor\u2026" }), children: usesWord ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2593
|
+
"div",
|
|
2594
|
+
{
|
|
2595
|
+
className: "-mx-5 -mb-3 flex min-h-[22rem] flex-1 flex-col border-t border-border/60",
|
|
2596
|
+
"data-testid": "mail-word-body",
|
|
2597
|
+
onSubmit: (event) => event.stopPropagation(),
|
|
2598
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2599
|
+
NativeDocxEditor,
|
|
2600
|
+
{
|
|
2601
|
+
compact: true,
|
|
2602
|
+
adapter: wordBody.adapter,
|
|
2603
|
+
documentId: wordBody.documentKey,
|
|
2604
|
+
title: "Email",
|
|
2605
|
+
stateRef: wordBody.stateRef
|
|
2606
|
+
}
|
|
2607
|
+
)
|
|
2608
|
+
}
|
|
2609
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2390
2610
|
MailBodyEditor,
|
|
2391
2611
|
{
|
|
2392
2612
|
text,
|
|
@@ -2454,7 +2674,7 @@ function MailComposerForm({
|
|
|
2454
2674
|
}
|
|
2455
2675
|
),
|
|
2456
2676
|
documents && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2457
|
-
|
|
2677
|
+
chunkDTBSGG36_cjs.MailDocumentPicker,
|
|
2458
2678
|
{
|
|
2459
2679
|
documents: documents.documents,
|
|
2460
2680
|
disabled: locked,
|
|
@@ -2553,6 +2773,7 @@ function ConnectedMailComposer({
|
|
|
2553
2773
|
drafts: draftsProp,
|
|
2554
2774
|
notify: notify3 = defaultMailNotify,
|
|
2555
2775
|
offline,
|
|
2776
|
+
replyTo,
|
|
2556
2777
|
...rest
|
|
2557
2778
|
}) {
|
|
2558
2779
|
const { client } = react$1.useMailClient();
|
|
@@ -2567,12 +2788,14 @@ function ConnectedMailComposer({
|
|
|
2567
2788
|
const draftsList = react$1.useMailMessages(account, draftsFolderId, "", null, {
|
|
2568
2789
|
enabled: !draftsProp && ready
|
|
2569
2790
|
});
|
|
2791
|
+
const [reloaded, setReloaded] = react.useState();
|
|
2792
|
+
const openId = reloaded ?? draftId;
|
|
2570
2793
|
const draft = react$1.useMailDraftCompose(
|
|
2571
2794
|
account,
|
|
2572
|
-
|
|
2795
|
+
openId,
|
|
2573
2796
|
async (from, id) => {
|
|
2574
2797
|
const message = await client.getMessage(from, id);
|
|
2575
|
-
return
|
|
2798
|
+
return chunkDTBSGG36_cjs.draftMailCompose(
|
|
2576
2799
|
message,
|
|
2577
2800
|
await hydrateMailAttachments(client, from, message.id, message.attachments, {
|
|
2578
2801
|
isOnline,
|
|
@@ -2580,14 +2803,20 @@ function ConnectedMailComposer({
|
|
|
2580
2803
|
})
|
|
2581
2804
|
);
|
|
2582
2805
|
},
|
|
2583
|
-
{ enabled: !initial && ready }
|
|
2584
|
-
);
|
|
2585
|
-
const start = react.useMemo(
|
|
2586
|
-
() => initial ?? (draftId ? draft.data : chunk3R6XBYL7_cjs.emptyMailCompose()),
|
|
2587
|
-
[initial, draftId, draft.data]
|
|
2806
|
+
{ enabled: (!initial || !!reloaded) && ready }
|
|
2588
2807
|
);
|
|
2808
|
+
const original = react$1.useMailMessage(account, replyTo, { enabled: !!replyTo && ready });
|
|
2809
|
+
const start = react.useMemo(() => {
|
|
2810
|
+
if (replyTo)
|
|
2811
|
+
return original.data && account ? {
|
|
2812
|
+
...chunkDTBSGG36_cjs.replyMailCompose(original.data, { account, folderRole: "inbox" }),
|
|
2813
|
+
text: "",
|
|
2814
|
+
html: ""
|
|
2815
|
+
} : void 0;
|
|
2816
|
+
return reloaded ? draft.data : initial ?? (openId ? draft.data : chunkDTBSGG36_cjs.emptyMailCompose());
|
|
2817
|
+
}, [replyTo, original.data, account, reloaded, initial, openId, draft.data]);
|
|
2589
2818
|
if (!start)
|
|
2590
|
-
return draft.error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "p-4 text-sm text-destructive", children: draft.error.message }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-4 text-sm text-muted-foreground", children: "Loading draft\u2026" });
|
|
2819
|
+
return draft.error ?? original.error ? /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "p-4 text-sm text-destructive", children: (draft.error ?? original.error)?.message }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-4 text-sm text-muted-foreground", children: "Loading draft\u2026" });
|
|
2591
2820
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2592
2821
|
MailComposerForm,
|
|
2593
2822
|
{
|
|
@@ -2598,9 +2827,10 @@ function ConnectedMailComposer({
|
|
|
2598
2827
|
drafts: draftsProp ?? draftsList.data?.messages ?? [],
|
|
2599
2828
|
notify: notify3,
|
|
2600
2829
|
offline,
|
|
2830
|
+
onReload: setReloaded,
|
|
2601
2831
|
...rest
|
|
2602
2832
|
},
|
|
2603
|
-
`${account?.id}-${
|
|
2833
|
+
`${account?.id}-${openId ?? ""}`
|
|
2604
2834
|
);
|
|
2605
2835
|
}
|
|
2606
2836
|
function ConnectedMailSetup({
|
|
@@ -2780,6 +3010,8 @@ function ConnectedMailbox({
|
|
|
2780
3010
|
offline,
|
|
2781
3011
|
documents,
|
|
2782
3012
|
saveToWorkspace,
|
|
3013
|
+
word,
|
|
3014
|
+
onReplyWithArbi,
|
|
2783
3015
|
renderInvite,
|
|
2784
3016
|
renderPanel = SidePanel,
|
|
2785
3017
|
onViewerOpenChange,
|
|
@@ -2809,6 +3041,7 @@ function ConnectedMailbox({
|
|
|
2809
3041
|
const [compose, setCompose] = react.useState(null);
|
|
2810
3042
|
const [composeLocalDraftId, setComposeLocalDraftId] = react.useState();
|
|
2811
3043
|
const [composeSession, setComposeSession] = react.useState(0);
|
|
3044
|
+
const [mailboxKey] = react.useState(() => crypto.randomUUID());
|
|
2812
3045
|
const openCompose = (value, localDraftId) => {
|
|
2813
3046
|
setComposeSession((n) => n + 1);
|
|
2814
3047
|
setComposeLocalDraftId(localDraftId);
|
|
@@ -2887,7 +3120,7 @@ function ConnectedMailbox({
|
|
|
2887
3120
|
const message = detail.data;
|
|
2888
3121
|
react.useEffect(() => {
|
|
2889
3122
|
if (!composeAttachments?.length) return;
|
|
2890
|
-
openCompose({ ...
|
|
3123
|
+
openCompose({ ...chunkDTBSGG36_cjs.emptyMailCompose(), attachments: composeAttachments });
|
|
2891
3124
|
onComposeOpened?.();
|
|
2892
3125
|
}, [composeAttachments]);
|
|
2893
3126
|
react.useEffect(() => {
|
|
@@ -2987,7 +3220,7 @@ function ConnectedMailbox({
|
|
|
2987
3220
|
const editDraft = async () => {
|
|
2988
3221
|
if (!message) return;
|
|
2989
3222
|
try {
|
|
2990
|
-
openCompose(
|
|
3223
|
+
openCompose(chunkDTBSGG36_cjs.draftMailCompose(message, await hydrate(message.attachments)));
|
|
2991
3224
|
} catch (e) {
|
|
2992
3225
|
setActionError(e instanceof Error ? e.message : "Could not load draft attachments");
|
|
2993
3226
|
}
|
|
@@ -2996,7 +3229,7 @@ function ConnectedMailbox({
|
|
|
2996
3229
|
if (!message || !account) return;
|
|
2997
3230
|
try {
|
|
2998
3231
|
const attachments = forward ? await hydrate(message.attachments) : [];
|
|
2999
|
-
openCompose(
|
|
3232
|
+
openCompose(chunkDTBSGG36_cjs.replyMailCompose(message, { account, folderRole, forward, all, attachments }));
|
|
3000
3233
|
} catch (e) {
|
|
3001
3234
|
setActionError(e instanceof Error ? e.message : "Could not prepare forwarded attachments");
|
|
3002
3235
|
}
|
|
@@ -3105,7 +3338,7 @@ function ConnectedMailbox({
|
|
|
3105
3338
|
{
|
|
3106
3339
|
size: "sm",
|
|
3107
3340
|
disabled: !ready || !!compose,
|
|
3108
|
-
onClick: () => openCompose(
|
|
3341
|
+
onClick: () => openCompose(chunkDTBSGG36_cjs.emptyMailCompose()),
|
|
3109
3342
|
children: [
|
|
3110
3343
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "mr-1.5 size-4" }),
|
|
3111
3344
|
"Email"
|
|
@@ -3184,7 +3417,7 @@ function ConnectedMailbox({
|
|
|
3184
3417
|
onEdit: (value) => openCompose({ ...value })
|
|
3185
3418
|
}),
|
|
3186
3419
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: deviceFolder ? "hidden" : "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3187
|
-
|
|
3420
|
+
chunkDTBSGG36_cjs.MailGrid,
|
|
3188
3421
|
{
|
|
3189
3422
|
messages: filteredMessages,
|
|
3190
3423
|
loading: list.isPending && list.fetchStatus !== "idle",
|
|
@@ -3231,6 +3464,8 @@ function ConnectedMailbox({
|
|
|
3231
3464
|
offline,
|
|
3232
3465
|
documents,
|
|
3233
3466
|
notify: notify3,
|
|
3467
|
+
word,
|
|
3468
|
+
sessionKey: `${mailboxKey}-${composeSession}`,
|
|
3234
3469
|
onChange: setCompose,
|
|
3235
3470
|
closeRequestRef: composeClose,
|
|
3236
3471
|
onClose: () => {
|
|
@@ -3246,7 +3481,7 @@ function ConnectedMailbox({
|
|
|
3246
3481
|
},
|
|
3247
3482
|
`${account?.id}-${composeSession}`
|
|
3248
3483
|
) : message && selected ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3249
|
-
|
|
3484
|
+
chunkDTBSGG36_cjs.MailMessageView,
|
|
3250
3485
|
{
|
|
3251
3486
|
account,
|
|
3252
3487
|
message,
|
|
@@ -3265,6 +3500,7 @@ function ConnectedMailbox({
|
|
|
3265
3500
|
onBack: () => setSelected(null),
|
|
3266
3501
|
onEditDraft: () => void editDraft(),
|
|
3267
3502
|
onReply: (forward, all) => void reply(forward, all),
|
|
3503
|
+
onReplyWithArbi: onReplyWithArbi && account.provider === "native" ? () => onReplyWithArbi(message, account) : void 0,
|
|
3268
3504
|
onUpdate: (body) => void update(body),
|
|
3269
3505
|
onDownloadAttachment: (a) => void downloadAttachment(a),
|
|
3270
3506
|
onDownloadOriginal: () => void download(
|
|
@@ -3320,6 +3556,85 @@ function ConnectedMailbox({
|
|
|
3320
3556
|
)
|
|
3321
3557
|
] });
|
|
3322
3558
|
}
|
|
3559
|
+
function ConnectedMailMessage({
|
|
3560
|
+
messageId,
|
|
3561
|
+
mailbox = "native",
|
|
3562
|
+
folderRole = "inbox",
|
|
3563
|
+
onClose,
|
|
3564
|
+
onCompose,
|
|
3565
|
+
onReplyWithArbi
|
|
3566
|
+
}) {
|
|
3567
|
+
const { client } = react$1.useMailClient();
|
|
3568
|
+
const isOnline = react$1.useMailOnline();
|
|
3569
|
+
const cache = react$1.useMailCache();
|
|
3570
|
+
const accounts = react$1.useMailAccounts();
|
|
3571
|
+
const account = resolveMailbox(accounts.data, mailbox);
|
|
3572
|
+
const unlock = react$1.useMailUnlock(account);
|
|
3573
|
+
const detail = react$1.useMailMessage(account, messageId, { enabled: !!unlock.data || !isOnline });
|
|
3574
|
+
const [error, setError] = react.useState("");
|
|
3575
|
+
const message = detail.data;
|
|
3576
|
+
if (!account || !message)
|
|
3577
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { role: detail.error ? "alert" : "status", className: "p-4 text-sm text-muted-foreground", children: detail.error?.message ?? "Loading message\u2026" });
|
|
3578
|
+
const update = async (body) => {
|
|
3579
|
+
try {
|
|
3580
|
+
await react$1.mailJson(
|
|
3581
|
+
client.fetch,
|
|
3582
|
+
`${react$1.accountPath(account.id)}/messages/${encodeURIComponent(message.id)}`,
|
|
3583
|
+
{
|
|
3584
|
+
method: "PATCH",
|
|
3585
|
+
body: JSON.stringify(body)
|
|
3586
|
+
}
|
|
3587
|
+
);
|
|
3588
|
+
await cache.refreshAll();
|
|
3589
|
+
if (body.folder_id || body.action) onClose();
|
|
3590
|
+
} catch (e) {
|
|
3591
|
+
setError(e instanceof Error ? e.message : "Could not update message");
|
|
3592
|
+
}
|
|
3593
|
+
};
|
|
3594
|
+
const download = async (path, name) => {
|
|
3595
|
+
try {
|
|
3596
|
+
saveFile(await (await client.fetch(path)).blob(), name);
|
|
3597
|
+
} catch (e) {
|
|
3598
|
+
setError(e instanceof Error ? e.message : "Download failed");
|
|
3599
|
+
}
|
|
3600
|
+
};
|
|
3601
|
+
const reply = async (forward = false, all = false) => {
|
|
3602
|
+
try {
|
|
3603
|
+
const attachments = forward ? await hydrateMailAttachments(client, account, message.id, message.attachments, {
|
|
3604
|
+
isOnline
|
|
3605
|
+
}) : [];
|
|
3606
|
+
onCompose(chunkDTBSGG36_cjs.replyMailCompose(message, { account, folderRole, forward, all, attachments }));
|
|
3607
|
+
} catch (e) {
|
|
3608
|
+
setError(e instanceof Error ? e.message : "Could not prepare forwarded attachments");
|
|
3609
|
+
}
|
|
3610
|
+
};
|
|
3611
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full min-h-0 flex-col", children: [
|
|
3612
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "px-4 pt-3 text-sm text-destructive", children: error }),
|
|
3613
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3614
|
+
chunkDTBSGG36_cjs.MailMessageView,
|
|
3615
|
+
{
|
|
3616
|
+
account,
|
|
3617
|
+
message,
|
|
3618
|
+
folderRole,
|
|
3619
|
+
folders: void 0,
|
|
3620
|
+
isOnline,
|
|
3621
|
+
loading: detail.isFetching,
|
|
3622
|
+
onBack: onClose,
|
|
3623
|
+
onEditDraft: () => void hydrateMailAttachments(client, account, message.id, message.attachments, {
|
|
3624
|
+
isOnline
|
|
3625
|
+
}).then((attachments) => onCompose(chunkDTBSGG36_cjs.draftMailCompose(message, attachments))).catch((e) => setError(e.message)),
|
|
3626
|
+
onReply: (forward, all) => void reply(forward, all),
|
|
3627
|
+
onReplyWithArbi: onReplyWithArbi && account.provider === "native" ? () => onReplyWithArbi(message, account) : void 0,
|
|
3628
|
+
onUpdate: (body) => void update(body),
|
|
3629
|
+
onDownloadAttachment: (a) => void download(attachmentPath(account.id, message.id, a.id), a.name),
|
|
3630
|
+
onDownloadOriginal: () => void download(
|
|
3631
|
+
`${react$1.accountPath(account.id)}/messages/${message.id}/original`,
|
|
3632
|
+
"original.eml"
|
|
3633
|
+
)
|
|
3634
|
+
}
|
|
3635
|
+
)
|
|
3636
|
+
] });
|
|
3637
|
+
}
|
|
3323
3638
|
function ActiveChat({ agentId, workspaceId }) {
|
|
3324
3639
|
const chat = react$1.useArbiChat({ agentId, workspaceId });
|
|
3325
3640
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3438,6 +3753,7 @@ exports.ConnectedIdentityVerification = ConnectedIdentityVerification;
|
|
|
3438
3753
|
exports.ConnectedLogoutDialog = ConnectedLogoutDialog;
|
|
3439
3754
|
exports.ConnectedMailAccounts = ConnectedMailAccounts;
|
|
3440
3755
|
exports.ConnectedMailComposer = ConnectedMailComposer;
|
|
3756
|
+
exports.ConnectedMailMessage = ConnectedMailMessage;
|
|
3441
3757
|
exports.ConnectedMailSetup = ConnectedMailSetup;
|
|
3442
3758
|
exports.ConnectedMailbox = ConnectedMailbox;
|
|
3443
3759
|
exports.ConnectedNotificationPreferences = ConnectedNotificationPreferences;
|