@arbidocs/blocks 0.4.84 → 0.4.86
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/dist/MailBodyEditor-5PIQLYVY.js +217 -0
- package/dist/MailBodyEditor-5PIQLYVY.js.map +1 -0
- package/dist/MailBodyEditor-D7MGJMLH.cjs +223 -0
- package/dist/MailBodyEditor-D7MGJMLH.cjs.map +1 -0
- package/dist/agents/index.cjs +282 -281
- package/dist/agents/index.js +7 -6
- package/dist/agents/workflows/StepBarFrame.d.ts +3 -1
- package/dist/agents/workflows/WorkflowRunner.d.ts +10 -1
- package/dist/agents/workflows/run.d.ts +24 -3
- package/dist/agents/workflows/stepWindow.d.ts +4 -2
- package/dist/agents/workflows/types.d.ts +5 -0
- package/dist/agents/workflows/useWorkflowView.d.ts +16 -1
- package/dist/chat/index.cjs +1 -1
- package/dist/chat/index.js +1 -1
- package/dist/chunk-3R6XBYL7.cjs +576 -0
- package/dist/chunk-3R6XBYL7.cjs.map +1 -0
- package/dist/{chunk-CKB64Z4R.js → chunk-4XJZ6AAY.js} +6 -245
- package/dist/chunk-4XJZ6AAY.js.map +1 -0
- package/dist/{chunk-B3WCKBJ7.cjs → chunk-5YXG342J.cjs} +6 -18
- package/dist/chunk-5YXG342J.cjs.map +1 -0
- package/dist/{chunk-SB5ZKOYN.js → chunk-7C35WXYB.js} +4 -63
- package/dist/chunk-7C35WXYB.js.map +1 -0
- package/dist/chunk-7RJTEWYM.js +362 -0
- package/dist/chunk-7RJTEWYM.js.map +1 -0
- package/dist/chunk-AFSOUS5X.cjs +253 -0
- package/dist/chunk-AFSOUS5X.cjs.map +1 -0
- package/dist/{chunk-F4RUCUXF.cjs → chunk-C2HRZSAT.cjs} +2 -63
- package/dist/chunk-C2HRZSAT.cjs.map +1 -0
- package/dist/{chunk-XA5S4776.cjs → chunk-IHYVK6F7.cjs} +52 -51
- package/dist/chunk-IHYVK6F7.cjs.map +1 -0
- package/dist/{chunk-CONIA2ZA.js → chunk-KHY4PYU7.js} +246 -146
- package/dist/chunk-KHY4PYU7.js.map +1 -0
- package/dist/chunk-LGX6UFYG.js +557 -0
- package/dist/chunk-LGX6UFYG.js.map +1 -0
- package/dist/chunk-O4YPVYPO.cjs +373 -0
- package/dist/chunk-O4YPVYPO.cjs.map +1 -0
- package/dist/chunk-R26OHONI.js +250 -0
- package/dist/chunk-R26OHONI.js.map +1 -0
- package/dist/{chunk-RYYYHPFU.cjs → chunk-RZUMQM7W.cjs} +246 -146
- package/dist/chunk-RZUMQM7W.cjs.map +1 -0
- package/dist/{chunk-RX35SMPR.js → chunk-S2NFD4QV.js} +8 -7
- package/dist/chunk-S2NFD4QV.js.map +1 -0
- package/dist/{chunk-YJQVLVBJ.cjs → chunk-S5HZBXZA.cjs} +2 -243
- package/dist/chunk-S5HZBXZA.cjs.map +1 -0
- package/dist/{chunk-GJV2G4FC.js → chunk-W7NZRZ54.js} +6 -18
- package/dist/chunk-W7NZRZ54.js.map +1 -0
- package/dist/{chunk-ZQYE7J3J.cjs → chunk-WRSBM6QN.cjs} +332 -94
- package/dist/chunk-WRSBM6QN.cjs.map +1 -0
- package/dist/{chunk-RSKSXEPW.js → chunk-X23U6QEJ.js} +324 -88
- package/dist/chunk-X23U6QEJ.js.map +1 -0
- package/dist/collaboration/index.cjs +100 -49
- package/dist/collaboration/index.js +4 -1
- package/dist/collaboration/mail/MailBodyEditor.d.ts +7 -0
- package/dist/collaboration/mail/MailDeliveryList.d.ts +8 -0
- package/dist/collaboration/mail/MailDocumentPicker.d.ts +15 -0
- package/dist/collaboration/mail/MailGrid.d.ts +17 -0
- package/dist/collaboration/mail/MailMessageView.d.ts +27 -0
- package/dist/collaboration/mail/PlainMailBodyEditor.d.ts +12 -0
- package/dist/collaboration/mail/index.d.ts +6 -0
- package/dist/collaboration/mail/mailCompose.d.ts +24 -0
- package/dist/connect/index.cjs +1673 -96
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.d.ts +2 -1
- package/dist/connect/index.js +1634 -63
- package/dist/connect/index.js.map +1 -1
- package/dist/connection/ConnectedSettings.d.ts +1 -4
- package/dist/connection/ConnectedTagTable.d.ts +32 -0
- package/dist/connection/mail/ConnectedMailAccounts.d.ts +21 -0
- package/dist/connection/mail/ConnectedMailComposer.d.ts +40 -0
- package/dist/connection/mail/ConnectedMailSetup.d.ts +16 -0
- package/dist/connection/mail/ConnectedMailbox.d.ts +65 -0
- package/dist/connection/mail/MailComposerForm.d.ts +25 -0
- package/dist/connection/mail/attachments.d.ts +13 -0
- package/dist/connection/mail/index.d.ts +6 -0
- package/dist/connection/mail/mailbox.d.ts +6 -0
- package/dist/connection/mail/types.d.ts +92 -0
- package/dist/connection/useConnectedWorkNotifications.d.ts +6 -0
- package/dist/connection/useWorkflowThread.d.ts +7 -2
- package/dist/facts/index.cjs +3 -3
- package/dist/facts/index.js +3 -3
- package/dist/files/index.cjs +48 -368
- package/dist/files/index.cjs.map +1 -1
- package/dist/files/index.js +11 -361
- package/dist/files/index.js.map +1 -1
- package/dist/home/index.cjs +1 -1
- package/dist/home/index.js +1 -1
- package/dist/index.cjs +496 -437
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +23 -20
- package/dist/index.js.map +1 -1
- package/dist/settings/PasswordChangeDialog.d.ts +9 -12
- package/dist/settings/index.cjs +44 -43
- package/dist/settings/index.cjs.map +1 -1
- package/dist/settings/index.js +3 -2
- package/dist/settings/index.js.map +1 -1
- package/dist/shell/index.cjs +2 -2
- package/dist/shell/index.js +2 -2
- package/dist/studio/index.cjs +1 -1
- package/dist/studio/index.js +1 -1
- package/dist/tags/TagColumnsEditor.d.ts +34 -0
- package/dist/tags/TagDetail.d.ts +13 -11
- package/dist/tags/TagTable.d.ts +99 -0
- package/dist/tags/TagsNav.d.ts +2 -2
- package/dist/tags/index.d.ts +7 -5
- package/dist/tags/{tagMatrixDocx.d.ts → tagTableDocx.d.ts} +12 -12
- package/dist/tags/tagTableModel.d.ts +47 -0
- package/dist/workflow-canvas/index.cjs +50 -49
- package/dist/workflow-canvas/index.cjs.map +1 -1
- package/dist/workflow-canvas/index.js +7 -6
- package/dist/workflow-canvas/index.js.map +1 -1
- package/package.json +29 -4
- package/dist/chunk-B3WCKBJ7.cjs.map +0 -1
- package/dist/chunk-CKB64Z4R.js.map +0 -1
- package/dist/chunk-CONIA2ZA.js.map +0 -1
- package/dist/chunk-F4RUCUXF.cjs.map +0 -1
- package/dist/chunk-GJV2G4FC.js.map +0 -1
- package/dist/chunk-RSKSXEPW.js.map +0 -1
- package/dist/chunk-RX35SMPR.js.map +0 -1
- package/dist/chunk-RYYYHPFU.cjs.map +0 -1
- package/dist/chunk-SB5ZKOYN.js.map +0 -1
- package/dist/chunk-XA5S4776.cjs.map +0 -1
- package/dist/chunk-YJQVLVBJ.cjs.map +0 -1
- package/dist/chunk-ZQYE7J3J.cjs.map +0 -1
- package/dist/connection/ConnectedTagMatrix.d.ts +0 -23
- package/dist/tags/TagMatrix.d.ts +0 -87
- package/dist/tags/tagMatrixModel.d.ts +0 -43
package/dist/connect/index.cjs
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunk5YXG342J_cjs = require('../chunk-5YXG342J.cjs');
|
|
5
5
|
var chunkXMBYDLZQ_cjs = require('../chunk-XMBYDLZQ.cjs');
|
|
6
6
|
var chunkTZR36PPP_cjs = require('../chunk-TZR36PPP.cjs');
|
|
7
7
|
var chunkMUMH3Z6K_cjs = require('../chunk-MUMH3Z6K.cjs');
|
|
8
8
|
var chunkJH6JTI76_cjs = require('../chunk-JH6JTI76.cjs');
|
|
9
9
|
require('../chunk-7YUFMNFW.cjs');
|
|
10
|
-
var
|
|
11
|
-
var
|
|
10
|
+
var chunkO4YPVYPO_cjs = require('../chunk-O4YPVYPO.cjs');
|
|
11
|
+
var chunkWRSBM6QN_cjs = require('../chunk-WRSBM6QN.cjs');
|
|
12
|
+
var chunkRZUMQM7W_cjs = require('../chunk-RZUMQM7W.cjs');
|
|
13
|
+
var chunkAFSOUS5X_cjs = require('../chunk-AFSOUS5X.cjs');
|
|
14
|
+
var chunk7RGLTF76_cjs = require('../chunk-7RGLTF76.cjs');
|
|
12
15
|
require('../chunk-DETZZBG2.cjs');
|
|
16
|
+
var chunk2EI7NCUA_cjs = require('../chunk-2EI7NCUA.cjs');
|
|
13
17
|
require('../chunk-7D737FLE.cjs');
|
|
14
18
|
var chunkQVBZESYQ_cjs = require('../chunk-QVBZESYQ.cjs');
|
|
15
19
|
require('../chunk-ADOKTJHV.cjs');
|
|
@@ -19,7 +23,10 @@ require('../chunk-B4SRYJLM.cjs');
|
|
|
19
23
|
require('../chunk-7UTB4PHM.cjs');
|
|
20
24
|
require('../chunk-PPCATBOY.cjs');
|
|
21
25
|
var chunkKDG6FER6_cjs = require('../chunk-KDG6FER6.cjs');
|
|
26
|
+
var chunk3R6XBYL7_cjs = require('../chunk-3R6XBYL7.cjs');
|
|
22
27
|
var chunkULWRNGGE_cjs = require('../chunk-ULWRNGGE.cjs');
|
|
28
|
+
require('../chunk-IXALYQT7.cjs');
|
|
29
|
+
require('../chunk-FX3K6LNZ.cjs');
|
|
23
30
|
require('../chunk-MHVNT4J3.cjs');
|
|
24
31
|
require('../chunk-DES3K4SD.cjs');
|
|
25
32
|
var react = require('react');
|
|
@@ -31,6 +38,7 @@ var artifacts = require('@arbidocs/react/artifacts');
|
|
|
31
38
|
var lucideReact = require('lucide-react');
|
|
32
39
|
var documentTools = require('@arbidocs/react/document-tools');
|
|
33
40
|
var shell = require('@arbidocs/react/shell');
|
|
41
|
+
var client = require('@arbidocs/client');
|
|
34
42
|
|
|
35
43
|
function ConnectionBoundWebSocket({ children }) {
|
|
36
44
|
const { status } = chunkMUMH3Z6K_cjs.useConnection();
|
|
@@ -190,7 +198,7 @@ function StreamedArtifact({
|
|
|
190
198
|
}
|
|
191
199
|
var STARTING = /* @__PURE__ */ new Set(["pending", "running"]);
|
|
192
200
|
function formValues(step, inputs) {
|
|
193
|
-
const fields =
|
|
201
|
+
const fields = chunkRZUMQM7W_cjs.stepFields(step);
|
|
194
202
|
if (!fields.length) return void 0;
|
|
195
203
|
if (step.kind === "form")
|
|
196
204
|
return Object.fromEntries(fields.map((f) => [f.name, inputs[f.name] ?? ""]));
|
|
@@ -228,7 +236,7 @@ function useWorkflowThread(workflow, options = {}) {
|
|
|
228
236
|
const { wsId } = chunkXMBYDLZQ_cjs.useWorkspaceDocs();
|
|
229
237
|
const [threadId, setThreadId] = react.useState(options.conversationId);
|
|
230
238
|
const [localInputs, setLocalInputs] = react.useState(
|
|
231
|
-
() =>
|
|
239
|
+
() => chunkRZUMQM7W_cjs.initialRunInputs(workflow, options.initialInputs)
|
|
232
240
|
);
|
|
233
241
|
const [edits, setEdits] = react.useState({});
|
|
234
242
|
const [localStates, setLocalStates] = react.useState({});
|
|
@@ -248,12 +256,12 @@ function useWorkflowThread(workflow, options = {}) {
|
|
|
248
256
|
);
|
|
249
257
|
const conversation = conversations.data?.find((c) => c.external_id === threadId);
|
|
250
258
|
const steps = react.useMemo(
|
|
251
|
-
() =>
|
|
259
|
+
() => chunkRZUMQM7W_cjs.workflowSteps(workflow).length > 0 ? chunkRZUMQM7W_cjs.workflowSteps(workflow) : chunkRZUMQM7W_cjs.fromPlanSteps(conversation?.plan?.steps ?? []),
|
|
252
260
|
[workflow, conversation?.plan?.steps]
|
|
253
261
|
);
|
|
254
262
|
const activity = react$1.useConversationActivity(threadId, { live: !!threadId });
|
|
255
263
|
const serverStates = react.useMemo(
|
|
256
|
-
() =>
|
|
264
|
+
() => chunkRZUMQM7W_cjs.stepStatesFromActivity(activity.data ?? []),
|
|
257
265
|
[activity.data]
|
|
258
266
|
);
|
|
259
267
|
const working = steps.some(
|
|
@@ -292,6 +300,43 @@ function useWorkflowThread(workflow, options = {}) {
|
|
|
292
300
|
},
|
|
293
301
|
[actOnStep, refresh]
|
|
294
302
|
);
|
|
303
|
+
const createThread = react.useCallback(
|
|
304
|
+
async (values, done) => {
|
|
305
|
+
await ensureWorkspaceOpen();
|
|
306
|
+
const created = await createWork.mutateAsync({
|
|
307
|
+
title: chunkRZUMQM7W_cjs.runThreadTitle(workflow, values).slice(0, 60),
|
|
308
|
+
description: workflow.description || null,
|
|
309
|
+
prompt: null,
|
|
310
|
+
skill_ref: null,
|
|
311
|
+
skill_inputs: values,
|
|
312
|
+
agent_ext_id: options.agentId ?? null,
|
|
313
|
+
auth_mode: "run_now_temp",
|
|
314
|
+
plan: {
|
|
315
|
+
goal: "",
|
|
316
|
+
criteria: [],
|
|
317
|
+
max_passes: 3,
|
|
318
|
+
documents: [],
|
|
319
|
+
steps: chunkRZUMQM7W_cjs.toPlanSteps(workflow, {
|
|
320
|
+
inputs: values,
|
|
321
|
+
resolveWorkflow: options.resolveWorkflow,
|
|
322
|
+
compose: options.compose
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
const id = created.external_id;
|
|
327
|
+
setThreadId(id);
|
|
328
|
+
if (done) setLocalStates((s) => ({ ...s, [done]: { status: "done" } }));
|
|
329
|
+
options.onStarted?.(id);
|
|
330
|
+
for (const [stepId, st] of Object.entries(localStates))
|
|
331
|
+
if (st.status === "skipped")
|
|
332
|
+
await actOnStep.mutateAsync({
|
|
333
|
+
conversationId: id,
|
|
334
|
+
body: { step: stepId, action: "skip" }
|
|
335
|
+
});
|
|
336
|
+
return id;
|
|
337
|
+
},
|
|
338
|
+
[ensureWorkspaceOpen, createWork, workflow, options, localStates, actOnStep]
|
|
339
|
+
);
|
|
295
340
|
const complete = react.useCallback(
|
|
296
341
|
async (step) => {
|
|
297
342
|
let values = inputs;
|
|
@@ -301,34 +346,7 @@ function useWorkflowThread(workflow, options = {}) {
|
|
|
301
346
|
setLocalInputs(values);
|
|
302
347
|
setEdits({});
|
|
303
348
|
}
|
|
304
|
-
|
|
305
|
-
if (!id) {
|
|
306
|
-
await ensureWorkspaceOpen();
|
|
307
|
-
const created = await createWork.mutateAsync({
|
|
308
|
-
title: chunkRYYYHPFU_cjs.runThreadTitle(workflow, values).slice(0, 60),
|
|
309
|
-
description: workflow.description || null,
|
|
310
|
-
prompt: null,
|
|
311
|
-
skill_ref: null,
|
|
312
|
-
skill_inputs: values,
|
|
313
|
-
agent_ext_id: options.agentId ?? null,
|
|
314
|
-
auth_mode: "run_now_temp",
|
|
315
|
-
plan: {
|
|
316
|
-
goal: "",
|
|
317
|
-
criteria: [],
|
|
318
|
-
max_passes: 3,
|
|
319
|
-
documents: [],
|
|
320
|
-
steps: chunkRYYYHPFU_cjs.toPlanSteps(workflow, {
|
|
321
|
-
inputs: values,
|
|
322
|
-
resolveWorkflow: options.resolveWorkflow,
|
|
323
|
-
compose: options.compose
|
|
324
|
-
})
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
id = created.external_id;
|
|
328
|
-
setThreadId(id);
|
|
329
|
-
setLocalStates((s) => ({ ...s, [step.id]: { status: "done" } }));
|
|
330
|
-
options.onStarted?.(id);
|
|
331
|
-
}
|
|
349
|
+
const id = threadId ?? await createThread(values, step.id);
|
|
332
350
|
const documents = step.kind === "upload" ? options.documentsFor?.(step.id) : void 0;
|
|
333
351
|
await act(id, {
|
|
334
352
|
step: step.id,
|
|
@@ -337,8 +355,17 @@ function useWorkflowThread(workflow, options = {}) {
|
|
|
337
355
|
...documents?.length ? { documents } : {}
|
|
338
356
|
});
|
|
339
357
|
},
|
|
340
|
-
[inputs, options, localStates, threadId,
|
|
358
|
+
[inputs, options, localStates, threadId, createThread, act]
|
|
341
359
|
);
|
|
360
|
+
const start = react.useCallback(async () => {
|
|
361
|
+
if (!threadId) {
|
|
362
|
+
await createThread(inputs);
|
|
363
|
+
await refresh();
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
await arbi.conversations.runWithAuth(threadId);
|
|
367
|
+
await refresh();
|
|
368
|
+
}, [threadId, createThread, inputs, arbi, refresh]);
|
|
342
369
|
const skip = react.useCallback(
|
|
343
370
|
async (stepId) => {
|
|
344
371
|
if (!threadId) {
|
|
@@ -372,7 +399,11 @@ function useWorkflowThread(workflow, options = {}) {
|
|
|
372
399
|
[threadId, act]
|
|
373
400
|
);
|
|
374
401
|
const loaded = !options.conversationId || activity.isSuccess || activity.isError;
|
|
375
|
-
const
|
|
402
|
+
const idle = !!conversation && !conversation.in_progress;
|
|
403
|
+
const anyRunning = Object.values(states).some((s) => s.status === "running");
|
|
404
|
+
const needsStart = !threadId || idle && !anyRunning;
|
|
405
|
+
const runError = idle ? conversation?.last_error ?? null : null;
|
|
406
|
+
const view = chunkRZUMQM7W_cjs.useWorkflowView({
|
|
376
407
|
steps,
|
|
377
408
|
states,
|
|
378
409
|
inputs,
|
|
@@ -380,6 +411,9 @@ function useWorkflowThread(workflow, options = {}) {
|
|
|
380
411
|
complete,
|
|
381
412
|
skip,
|
|
382
413
|
retry,
|
|
414
|
+
start,
|
|
415
|
+
needsStart,
|
|
416
|
+
runError,
|
|
383
417
|
sendBack,
|
|
384
418
|
decline,
|
|
385
419
|
nameOf,
|
|
@@ -448,7 +482,7 @@ function WorkflowSignDialog({
|
|
|
448
482
|
const arbi = react$1.useArbi();
|
|
449
483
|
const { user, ensureWorkspaceOpen } = chunkMUMH3Z6K_cjs.useConnection();
|
|
450
484
|
const tools = documentTools.useOptionalDocumentTools();
|
|
451
|
-
const { id, version: stepVersion } =
|
|
485
|
+
const { id, version: stepVersion } = chunkRZUMQM7W_cjs.splitDocRef(docRef);
|
|
452
486
|
const [version, setVersion] = react.useState(stepVersion);
|
|
453
487
|
const [pdf, setPdf] = react.useState(null);
|
|
454
488
|
const [preparing, setPreparing] = react.useState(false);
|
|
@@ -526,7 +560,7 @@ function WorkflowWordDialog({
|
|
|
526
560
|
onClose,
|
|
527
561
|
labels
|
|
528
562
|
}) {
|
|
529
|
-
const { id } =
|
|
563
|
+
const { id } = chunkRZUMQM7W_cjs.splitDocRef(docRef);
|
|
530
564
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
531
565
|
chunkULWRNGGE_cjs.ModalScaffold,
|
|
532
566
|
{
|
|
@@ -660,7 +694,7 @@ function ConnectedWorkflowRunner({
|
|
|
660
694
|
() => ({
|
|
661
695
|
me: user?.externalId,
|
|
662
696
|
openDocument: onOpenDocument && ((ref) => {
|
|
663
|
-
const { id, version } =
|
|
697
|
+
const { id, version } = chunkRZUMQM7W_cjs.splitDocRef(ref);
|
|
664
698
|
onOpenDocument(id, version);
|
|
665
699
|
}),
|
|
666
700
|
openDraft: onOpenDraft && ((draftId) => onOpenDraft(draftId)),
|
|
@@ -670,7 +704,7 @@ function ConnectedWorkflowRunner({
|
|
|
670
704
|
const w = state.waiting;
|
|
671
705
|
if (w?.doc_ext_id) setDialog({ kind: "sign", docRef: w.doc_ext_id });
|
|
672
706
|
}),
|
|
673
|
-
openRedline: hostActions?.openRedline ?? ((ref) => setDialog({ kind: "word", docRef: ref, title: nameOfDoc(
|
|
707
|
+
openRedline: hostActions?.openRedline ?? ((ref) => setDialog({ kind: "word", docRef: ref, title: nameOfDoc(chunkRZUMQM7W_cjs.splitDocRef(ref).id) ?? "" })),
|
|
674
708
|
openReview: hostActions?.openReview ?? ((tags, documents) => setDialog({ kind: "review", tags, documents }))
|
|
675
709
|
}),
|
|
676
710
|
[user?.externalId, onOpenDocument, onOpenDraft, onOpenMessage, hostActions, nameOfDoc, inThread]
|
|
@@ -806,7 +840,7 @@ function ConnectedWorkflowRunner({
|
|
|
806
840
|
);
|
|
807
841
|
};
|
|
808
842
|
const runner = (compact) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
809
|
-
|
|
843
|
+
chunkRZUMQM7W_cjs.WorkflowRunner,
|
|
810
844
|
{
|
|
811
845
|
people,
|
|
812
846
|
...runnerProps,
|
|
@@ -852,10 +886,10 @@ function ConnectedWorkflowRunner({
|
|
|
852
886
|
) }),
|
|
853
887
|
inThread && conversationId ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
854
888
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
855
|
-
|
|
889
|
+
chunkRZUMQM7W_cjs.WorkflowStepBar,
|
|
856
890
|
{
|
|
857
891
|
run: view,
|
|
858
|
-
levels:
|
|
892
|
+
levels: chunkRZUMQM7W_cjs.stepLevels(view.steps),
|
|
859
893
|
doneTitle: (workflow.run.kind === "steps" ? workflow.run.completion?.title : void 0) ?? runnerProps.labels?.complete ?? "Done",
|
|
860
894
|
icon: (key) => key && runnerProps.renderIcon ? runnerProps.renderIcon(key) : void 0,
|
|
861
895
|
tid: (suffix) => `${testIdPrefix}-${suffix}`
|
|
@@ -988,7 +1022,17 @@ function ReviewNotify({
|
|
|
988
1022
|
] })
|
|
989
1023
|
] });
|
|
990
1024
|
}
|
|
991
|
-
|
|
1025
|
+
var FLAT_KINDS = ["issue", "person", "organisation"];
|
|
1026
|
+
var KIND_TITLES = {
|
|
1027
|
+
label: "Labels",
|
|
1028
|
+
annotation: "Annotations",
|
|
1029
|
+
search: "Searches",
|
|
1030
|
+
issue: "Issues",
|
|
1031
|
+
person: "People",
|
|
1032
|
+
organisation: "Organisations"
|
|
1033
|
+
};
|
|
1034
|
+
function ConnectedTagTable({
|
|
1035
|
+
kind,
|
|
992
1036
|
parentId,
|
|
993
1037
|
linksLimit = 3,
|
|
994
1038
|
exportTitle,
|
|
@@ -999,8 +1043,16 @@ function ConnectedTagMatrix({
|
|
|
999
1043
|
}) {
|
|
1000
1044
|
const arbi = react$1.useArbi();
|
|
1001
1045
|
const { workspaceId, status, ensureWorkspaceOpen } = chunkMUMH3Z6K_cjs.useConnection();
|
|
1002
|
-
const
|
|
1003
|
-
const
|
|
1046
|
+
const schema = react$1.useTagKindSchema(kind);
|
|
1047
|
+
const rows = react$1.useTags(workspaceId ?? void 0, {
|
|
1048
|
+
kind,
|
|
1049
|
+
...parentId ? { parentId } : {},
|
|
1050
|
+
include: ["links"],
|
|
1051
|
+
linksLimit
|
|
1052
|
+
});
|
|
1053
|
+
const canAddRows = !readOnly && kind !== "annotation" && kind !== "search";
|
|
1054
|
+
const setValues = react$1.useSetTagValues();
|
|
1055
|
+
const updateSchema = react$1.useUpdateTagKindSchema();
|
|
1004
1056
|
const invalidate = react$1.useInvalidateTagData();
|
|
1005
1057
|
const members = react$1.useWorkspaceUsers(workspaceId ?? void 0, {
|
|
1006
1058
|
enabled: status === "authenticated" && !!workspaceId,
|
|
@@ -1011,45 +1063,59 @@ function ConnectedTagMatrix({
|
|
|
1011
1063
|
value: m.user.external_id,
|
|
1012
1064
|
label: [m.user.given_name, m.user.family_name].filter(Boolean).join(" ") || m.user.email
|
|
1013
1065
|
}));
|
|
1066
|
+
const table = react.useMemo(
|
|
1067
|
+
() => schema.data && rows.data ? { columns: schema.data.fields, rows: rows.data } : void 0,
|
|
1068
|
+
[schema.data, rows.data]
|
|
1069
|
+
);
|
|
1014
1070
|
const fail = (e) => setError(e instanceof Error ? e.message : String(e));
|
|
1015
1071
|
const snapshot = (data) => {
|
|
1016
|
-
const title = exportTitle ??
|
|
1017
|
-
const bytes =
|
|
1072
|
+
const title = exportTitle ?? KIND_TITLES[kind];
|
|
1073
|
+
const bytes = chunkWRSBM6QN_cjs.tagTableDocx(data, {
|
|
1018
1074
|
title,
|
|
1019
1075
|
nameOf: (id) => people.find((p) => p.value === id)?.label
|
|
1020
1076
|
});
|
|
1021
1077
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1022
1078
|
const name = `${title.replace(/[\\/:*?"<>|]+/g, "-")} (${stamp}).docx`;
|
|
1023
|
-
return { blob: new Blob([bytes], { type:
|
|
1079
|
+
return { blob: new Blob([bytes], { type: chunkWRSBM6QN_cjs.DOCX_MIME_TYPE }), name };
|
|
1024
1080
|
};
|
|
1025
1081
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1026
1082
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1027
|
-
|
|
1083
|
+
chunkWRSBM6QN_cjs.TagTable,
|
|
1028
1084
|
{
|
|
1029
1085
|
...props,
|
|
1030
|
-
|
|
1031
|
-
isLoading:
|
|
1086
|
+
table,
|
|
1087
|
+
isLoading: schema.isLoading || rows.isLoading,
|
|
1032
1088
|
people,
|
|
1033
1089
|
onChangeValue: readOnly ? void 0 : async (tagId, fieldId, value) => {
|
|
1034
1090
|
setError(null);
|
|
1035
|
-
await
|
|
1091
|
+
await setValues.mutateAsync({ tagId, values: { [fieldId]: value } }).catch(fail);
|
|
1092
|
+
},
|
|
1093
|
+
onChangeColumns: readOnly ? void 0 : async (fields) => {
|
|
1094
|
+
setError(null);
|
|
1095
|
+
await ensureWorkspaceOpen();
|
|
1096
|
+
await updateSchema.mutateAsync({ kind, fields }).catch((e) => {
|
|
1097
|
+
fail(e);
|
|
1098
|
+
throw e;
|
|
1099
|
+
});
|
|
1036
1100
|
},
|
|
1037
|
-
onAddRow:
|
|
1101
|
+
onAddRow: !canAddRows ? void 0 : async (name) => {
|
|
1038
1102
|
setError(null);
|
|
1039
1103
|
try {
|
|
1040
1104
|
await ensureWorkspaceOpen();
|
|
1041
|
-
await arbi.tags.create({
|
|
1105
|
+
await arbi.tags.create({
|
|
1106
|
+
name,
|
|
1107
|
+
kind,
|
|
1108
|
+
...parentId && !FLAT_KINDS.includes(kind) ? { parentId } : {}
|
|
1109
|
+
});
|
|
1042
1110
|
await invalidate();
|
|
1043
1111
|
} catch (e) {
|
|
1044
1112
|
fail(e);
|
|
1045
1113
|
}
|
|
1046
1114
|
},
|
|
1047
|
-
onExport: onExported &&
|
|
1115
|
+
onExport: onExported && table ? async () => {
|
|
1048
1116
|
setError(null);
|
|
1049
1117
|
try {
|
|
1050
|
-
const
|
|
1051
|
-
if (!data) return;
|
|
1052
|
-
const { blob, name } = snapshot(data);
|
|
1118
|
+
const { blob, name } = snapshot(table);
|
|
1053
1119
|
await ensureWorkspaceOpen();
|
|
1054
1120
|
const uploaded = await arbi.documents.uploadFile(blob, name);
|
|
1055
1121
|
const id = uploaded?.doc_ext_ids?.[0];
|
|
@@ -1058,12 +1124,10 @@ function ConnectedTagMatrix({
|
|
|
1058
1124
|
fail(e);
|
|
1059
1125
|
}
|
|
1060
1126
|
} : void 0,
|
|
1061
|
-
onDownload: downloadable &&
|
|
1127
|
+
onDownload: downloadable && table ? () => {
|
|
1062
1128
|
setError(null);
|
|
1063
1129
|
try {
|
|
1064
|
-
const
|
|
1065
|
-
if (!data) return;
|
|
1066
|
-
const { blob, name } = snapshot(data);
|
|
1130
|
+
const { blob, name } = snapshot(table);
|
|
1067
1131
|
const url = URL.createObjectURL(blob);
|
|
1068
1132
|
const link = document.createElement("a");
|
|
1069
1133
|
link.href = url;
|
|
@@ -1154,12 +1218,12 @@ function ConnectedProfileCard({ notify: notify3, title = "Profile" }) {
|
|
|
1154
1218
|
}
|
|
1155
1219
|
});
|
|
1156
1220
|
const display = profile?.fullName || user?.name || "Unnamed";
|
|
1157
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1158
|
-
|
|
1221
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunk5YXG342J_cjs.SettingsSection, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserCircle, {}), title, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1222
|
+
chunk5YXG342J_cjs.ProfileCard,
|
|
1159
1223
|
{
|
|
1160
1224
|
avatar: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1161
1225
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1162
|
-
|
|
1226
|
+
chunk5YXG342J_cjs.AvatarPicker,
|
|
1163
1227
|
{
|
|
1164
1228
|
pictureUrl: profile?.picture ?? user?.picture,
|
|
1165
1229
|
initials: chunkKDG6FER6_cjs.initials(display),
|
|
@@ -1201,9 +1265,9 @@ function ConnectedIdentityVerification({
|
|
|
1201
1265
|
onNameAccepted: () => notify3?.("Name updated to match your ID", "success")
|
|
1202
1266
|
});
|
|
1203
1267
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1204
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1268
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk5YXG342J_cjs.IdentityVerificationCard, { flow, labels }),
|
|
1205
1269
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1206
|
-
|
|
1270
|
+
chunk5YXG342J_cjs.IdentityVerificationDialog,
|
|
1207
1271
|
{
|
|
1208
1272
|
flow,
|
|
1209
1273
|
accountName: profile?.fullName ?? "",
|
|
@@ -1215,7 +1279,7 @@ function ConnectedIdentityVerification({
|
|
|
1215
1279
|
function ConnectedRequireVerified({ children, labels }) {
|
|
1216
1280
|
const { data: profile } = react$1.useProfile();
|
|
1217
1281
|
const flow = react$1.useIdentityVerification();
|
|
1218
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1282
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunk5YXG342J_cjs.RequireVerified, { flow, accountName: profile?.fullName ?? "", labels, children });
|
|
1219
1283
|
}
|
|
1220
1284
|
function defaultUnmetPasswordRequirement(password) {
|
|
1221
1285
|
if (password.length < 8) return "Minimum 8 characters";
|
|
@@ -1228,29 +1292,25 @@ function defaultUnmetPasswordRequirement(password) {
|
|
|
1228
1292
|
function ConnectedSecuritySection({
|
|
1229
1293
|
notify: notify3,
|
|
1230
1294
|
getUnmetRequirement = defaultUnmetPasswordRequirement,
|
|
1231
|
-
renderRecoveryKey,
|
|
1232
1295
|
children
|
|
1233
1296
|
}) {
|
|
1234
1297
|
const [open, setOpen] = react.useState(false);
|
|
1235
1298
|
const change = react$1.usePasswordChange();
|
|
1236
|
-
const { data: workspaces } = react$1.useWorkspaces({ enabled: open });
|
|
1237
|
-
const workspaceCount = (workspaces ?? []).filter((w) => w.is_member).length;
|
|
1238
1299
|
const form = react$1.usePasswordChangeForm({
|
|
1239
1300
|
getUnmetRequirement,
|
|
1240
1301
|
submit: async (vars) => {
|
|
1241
|
-
|
|
1302
|
+
await change.mutateAsync(vars);
|
|
1242
1303
|
notify3?.("Password changed successfully", "success");
|
|
1243
|
-
return result;
|
|
1244
1304
|
},
|
|
1245
1305
|
onClose: () => setOpen(false)
|
|
1246
1306
|
});
|
|
1247
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1248
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1307
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(chunk5YXG342J_cjs.SettingsSection, { icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.KeyRound, {}), title: "Security", children: [
|
|
1308
|
+
/* @__PURE__ */ jsxRuntime.jsxs(chunk5YXG342J_cjs.SettingsCard, { padding: "sm", children: [
|
|
1249
1309
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1250
|
-
|
|
1310
|
+
chunk5YXG342J_cjs.SettingsActionRow,
|
|
1251
1311
|
{
|
|
1252
1312
|
title: "Change password",
|
|
1253
|
-
description: "Used to sign in and to
|
|
1313
|
+
description: "Used to sign in and to unlock your account key. Changing it keeps everything readable and re-encrypts nothing.",
|
|
1254
1314
|
onClick: () => setOpen(true),
|
|
1255
1315
|
testId: "change-password-button"
|
|
1256
1316
|
}
|
|
@@ -1258,7 +1318,7 @@ function ConnectedSecuritySection({
|
|
|
1258
1318
|
children
|
|
1259
1319
|
] }),
|
|
1260
1320
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1261
|
-
|
|
1321
|
+
chunk5YXG342J_cjs.PasswordChangeDialog,
|
|
1262
1322
|
{
|
|
1263
1323
|
open,
|
|
1264
1324
|
onClose: form.onCancel,
|
|
@@ -1270,35 +1330,34 @@ function ConnectedSecuritySection({
|
|
|
1270
1330
|
confirmPassword: form.confirmPassword,
|
|
1271
1331
|
onConfirmPasswordChange: form.onConfirmPasswordChange,
|
|
1272
1332
|
getUnmetRequirement,
|
|
1273
|
-
workspaceCount,
|
|
1274
1333
|
error: form.error,
|
|
1275
1334
|
isProcessing: form.isProcessing,
|
|
1276
1335
|
isSubmitDisabled: form.isSubmitDisabled,
|
|
1277
1336
|
onSubmit: form.onSubmit,
|
|
1278
|
-
|
|
1337
|
+
isChanged: form.isChanged,
|
|
1279
1338
|
onDone: form.onDone
|
|
1280
1339
|
}
|
|
1281
1340
|
)
|
|
1282
1341
|
] });
|
|
1283
1342
|
}
|
|
1284
1343
|
function ConnectedNotificationPreferences({
|
|
1285
|
-
categories =
|
|
1344
|
+
categories = chunk5YXG342J_cjs.EMAIL_NOTIFICATION_CATEGORIES,
|
|
1286
1345
|
title = "Notifications"
|
|
1287
1346
|
}) {
|
|
1288
1347
|
const keys = react.useMemo(
|
|
1289
|
-
() => categories ===
|
|
1348
|
+
() => categories === chunk5YXG342J_cjs.EMAIL_NOTIFICATION_CATEGORIES ? chunk5YXG342J_cjs.EMAIL_NOTIFICATION_KEYS : categories.map((c) => c.key),
|
|
1290
1349
|
[categories]
|
|
1291
1350
|
);
|
|
1292
1351
|
const prefs = react$1.useNotificationPreferences(keys);
|
|
1293
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1294
|
-
|
|
1352
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunk5YXG342J_cjs.SettingsSection, { title, children: /* @__PURE__ */ jsxRuntime.jsx(chunk5YXG342J_cjs.SettingsCard, { className: "space-y-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1353
|
+
chunk5YXG342J_cjs.NotificationCategoryList,
|
|
1295
1354
|
{
|
|
1296
1355
|
masterId: "emailNotifications",
|
|
1297
1356
|
masterTitle: "Email Notifications",
|
|
1298
1357
|
masterDescription: "Email me about activity when I\u2019m away",
|
|
1299
1358
|
masterChecked: prefs.masterChecked,
|
|
1300
1359
|
onMasterChange: prefs.setAll,
|
|
1301
|
-
categories:
|
|
1360
|
+
categories: chunk5YXG342J_cjs.toNotificationCategories(prefs.checked, categories),
|
|
1302
1361
|
onCategoryChange: prefs.setCategory
|
|
1303
1362
|
}
|
|
1304
1363
|
) }) });
|
|
@@ -1312,14 +1371,14 @@ function ConnectedSessionsRow({
|
|
|
1312
1371
|
const sessions = react$1.useSessions({ enabled: open });
|
|
1313
1372
|
const currentSessionId = react$1.useCurrentSessionId();
|
|
1314
1373
|
const terminate = react$1.useTerminateSession();
|
|
1315
|
-
const views =
|
|
1374
|
+
const views = chunk5YXG342J_cjs.toActiveSessionViews(sessions.data ?? [], {
|
|
1316
1375
|
currentSessionId,
|
|
1317
1376
|
terminatingId: terminate.isPending ? terminate.variables : null,
|
|
1318
1377
|
renderIcon: renderSessionIcon
|
|
1319
1378
|
});
|
|
1320
1379
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1321
1380
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1322
|
-
|
|
1381
|
+
chunk5YXG342J_cjs.SettingsRow,
|
|
1323
1382
|
{
|
|
1324
1383
|
label: "Active sessions",
|
|
1325
1384
|
description: "Devices and agents currently signed in to your account.",
|
|
@@ -1341,7 +1400,7 @@ function ConnectedSessionsRow({
|
|
|
1341
1400
|
}
|
|
1342
1401
|
),
|
|
1343
1402
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1344
|
-
|
|
1403
|
+
chunk5YXG342J_cjs.ActiveSessionsDialog,
|
|
1345
1404
|
{
|
|
1346
1405
|
open,
|
|
1347
1406
|
onOpenChange: setOpen,
|
|
@@ -1376,7 +1435,7 @@ function ConnectedLogoutDialog({
|
|
|
1376
1435
|
const sessions = react$1.useSessions({ enabled: open });
|
|
1377
1436
|
const logoutAll = react$1.useLogoutAllSessions();
|
|
1378
1437
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1379
|
-
|
|
1438
|
+
chunk5YXG342J_cjs.LogoutDialog,
|
|
1380
1439
|
{
|
|
1381
1440
|
open,
|
|
1382
1441
|
onClose,
|
|
@@ -1390,7 +1449,7 @@ function ConnectedLogoutDialog({
|
|
|
1390
1449
|
},
|
|
1391
1450
|
canLogoutAll: true,
|
|
1392
1451
|
isOnline,
|
|
1393
|
-
sessions:
|
|
1452
|
+
sessions: chunk5YXG342J_cjs.toLogoutSessionViews(sessions.data ?? []),
|
|
1394
1453
|
renderSessionIcon
|
|
1395
1454
|
}
|
|
1396
1455
|
);
|
|
@@ -1409,7 +1468,7 @@ function ConnectedDangerZone({ notify: notify3, renderSubscriptionLink }) {
|
|
|
1409
1468
|
});
|
|
1410
1469
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1411
1470
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1412
|
-
|
|
1471
|
+
chunk5YXG342J_cjs.SettingsDangerZone,
|
|
1413
1472
|
{
|
|
1414
1473
|
isOpen: zoneOpen,
|
|
1415
1474
|
onToggle: () => setZoneOpen((o) => !o),
|
|
@@ -1429,12 +1488,12 @@ function ConnectedDangerZone({ notify: notify3, renderSubscriptionLink }) {
|
|
|
1429
1488
|
}
|
|
1430
1489
|
),
|
|
1431
1490
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1432
|
-
|
|
1491
|
+
chunk5YXG342J_cjs.DeleteAccountDialog,
|
|
1433
1492
|
{
|
|
1434
1493
|
open: dialogOpen,
|
|
1435
1494
|
onClose: flow.onClose,
|
|
1436
1495
|
step: flow.step,
|
|
1437
|
-
blockers:
|
|
1496
|
+
blockers: chunk5YXG342J_cjs.toDeleteBlockerViews(flow.blockers, renderSubscriptionLink),
|
|
1438
1497
|
onContinue: flow.onContinue,
|
|
1439
1498
|
onBack: flow.onBack,
|
|
1440
1499
|
userEmail: user?.email ?? "",
|
|
@@ -1597,6 +1656,14 @@ function mapWorkNotification(note) {
|
|
|
1597
1656
|
return null;
|
|
1598
1657
|
}
|
|
1599
1658
|
}
|
|
1659
|
+
if (note.type === "mail_draft_ready") {
|
|
1660
|
+
const draftId = react$1.mailDraftIdFromContent(note.content);
|
|
1661
|
+
if (!draftId) return null;
|
|
1662
|
+
return {
|
|
1663
|
+
title: `${sender} left a draft email for you to review`,
|
|
1664
|
+
target: { kind: "mail_draft", draftId, mailbox: "native" }
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1600
1667
|
const titles = {
|
|
1601
1668
|
mention: `${sender} mentioned you in a conversation`,
|
|
1602
1669
|
workspace_access_request: `${sender} needs workspace access to run a task`,
|
|
@@ -1616,6 +1683,1510 @@ function mapWorkNotification(note) {
|
|
|
1616
1683
|
}
|
|
1617
1684
|
};
|
|
1618
1685
|
}
|
|
1686
|
+
function attachmentPath(accountId, messageId, attachmentId) {
|
|
1687
|
+
return `${react$1.accountPath(accountId)}/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachmentId)}`;
|
|
1688
|
+
}
|
|
1689
|
+
function saveFile(blob, name) {
|
|
1690
|
+
const url = URL.createObjectURL(blob);
|
|
1691
|
+
const link = document.createElement("a");
|
|
1692
|
+
link.href = url;
|
|
1693
|
+
link.download = name;
|
|
1694
|
+
link.click();
|
|
1695
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
1696
|
+
}
|
|
1697
|
+
function hydrateMailAttachments(client$1, account, messageId, attachments, { isOnline, offline }) {
|
|
1698
|
+
return Promise.all(
|
|
1699
|
+
attachments.map(async (a) => {
|
|
1700
|
+
if (a.content_base64 != null) return a;
|
|
1701
|
+
if (!isOnline) {
|
|
1702
|
+
const file = await offline?.loadAttachment(account.id, messageId, a);
|
|
1703
|
+
return file ? { ...a, content_base64: client.bytesToBase64(new Uint8Array(await file.arrayBuffer())) } : { ...a, content_base64: null };
|
|
1704
|
+
}
|
|
1705
|
+
const response = await client$1.fetch(attachmentPath(account.id, messageId, a.id));
|
|
1706
|
+
return react$1.fileAttachment(new File([await response.blob()], a.name, { type: a.content_type }));
|
|
1707
|
+
})
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1710
|
+
function ConnectedMailAccounts({
|
|
1711
|
+
policy,
|
|
1712
|
+
accounts,
|
|
1713
|
+
onClose,
|
|
1714
|
+
embedded = false,
|
|
1715
|
+
user,
|
|
1716
|
+
oauthReturnPath,
|
|
1717
|
+
settings
|
|
1718
|
+
}) {
|
|
1719
|
+
const { client } = react$1.useMailClient();
|
|
1720
|
+
const [profileId, setProfileId] = react.useState(policy.server_profiles[0]?.id ?? "");
|
|
1721
|
+
const [email, setEmail] = react.useState("");
|
|
1722
|
+
const [username, setUsername] = react.useState("");
|
|
1723
|
+
const [password, setPassword] = react.useState("");
|
|
1724
|
+
const [error, setError] = react.useState("");
|
|
1725
|
+
const [alias, setAlias] = react.useState(() => react$1.defaultMailAlias(user));
|
|
1726
|
+
const native = react$1.useClaimNativeAlias(onClose);
|
|
1727
|
+
const isOnline = react$1.useMailOnline();
|
|
1728
|
+
const offline = !isOnline;
|
|
1729
|
+
const onNativeError = (err) => {
|
|
1730
|
+
if (!react$1.isAliasTakenError(err)) return setError(err.message);
|
|
1731
|
+
const suggestion = react$1.nextAliasSuggestion(alias);
|
|
1732
|
+
setAlias(suggestion);
|
|
1733
|
+
setError(react$1.aliasTakenMessage(alias, suggestion, policy.native_domain));
|
|
1734
|
+
};
|
|
1735
|
+
const connect = react$1.useConnectMailAccount();
|
|
1736
|
+
const disconnect = react$1.useDisconnectMailAccount();
|
|
1737
|
+
const authorizeOAuth = client.authorizeOAuth;
|
|
1738
|
+
const oauth = async (vendor) => {
|
|
1739
|
+
if (!authorizeOAuth) return;
|
|
1740
|
+
try {
|
|
1741
|
+
window.location.assign(
|
|
1742
|
+
await authorizeOAuth(
|
|
1743
|
+
vendor,
|
|
1744
|
+
oauthReturnPath ?? `${window.location.pathname}${window.location.search}`
|
|
1745
|
+
)
|
|
1746
|
+
);
|
|
1747
|
+
} catch (err) {
|
|
1748
|
+
setError(err instanceof Error ? err.message : "Could not connect account");
|
|
1749
|
+
}
|
|
1750
|
+
};
|
|
1751
|
+
const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1752
|
+
offline && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1753
|
+
"p",
|
|
1754
|
+
{
|
|
1755
|
+
role: "status",
|
|
1756
|
+
className: "mb-4 rounded bg-muted/40 px-3 py-2 text-sm text-muted-foreground",
|
|
1757
|
+
children: "You're offline. Creating, connecting or removing accounts needs a connection."
|
|
1758
|
+
}
|
|
1759
|
+
),
|
|
1760
|
+
policy.native_enabled && !accounts.some((a) => a.provider === "native") && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1761
|
+
"form",
|
|
1762
|
+
{
|
|
1763
|
+
className: "mb-5 grid gap-3",
|
|
1764
|
+
onSubmit: (e) => {
|
|
1765
|
+
e.preventDefault();
|
|
1766
|
+
native.mutate(alias, { onError: onNativeError });
|
|
1767
|
+
},
|
|
1768
|
+
children: [
|
|
1769
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "grid gap-1 text-sm", children: [
|
|
1770
|
+
"Choose your email address",
|
|
1771
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1772
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1773
|
+
"input",
|
|
1774
|
+
{
|
|
1775
|
+
"aria-label": "Email alias",
|
|
1776
|
+
required: true,
|
|
1777
|
+
pattern: "[a-z0-9][a-z0-9._\\-]{0,62}",
|
|
1778
|
+
className: "min-w-0 flex-1 rounded border bg-background p-2",
|
|
1779
|
+
value: alias,
|
|
1780
|
+
onChange: (e) => setAlias(e.target.value.toLowerCase())
|
|
1781
|
+
}
|
|
1782
|
+
),
|
|
1783
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
1784
|
+
"@",
|
|
1785
|
+
policy.native_domain
|
|
1786
|
+
] })
|
|
1787
|
+
] })
|
|
1788
|
+
] }),
|
|
1789
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled: native.isPending || offline, type: "submit", children: "Create inbox" })
|
|
1790
|
+
]
|
|
1791
|
+
}
|
|
1792
|
+
),
|
|
1793
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-4 text-sm text-muted-foreground", children: "Connect an account using the providers enabled by your administrator." }),
|
|
1794
|
+
authorizeOAuth && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 flex flex-wrap gap-2", children: policy.oauth_providers.map((vendor) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1795
|
+
ui.Button,
|
|
1796
|
+
{
|
|
1797
|
+
variant: "outline",
|
|
1798
|
+
disabled: offline,
|
|
1799
|
+
onClick: () => void oauth(vendor),
|
|
1800
|
+
children: [
|
|
1801
|
+
"Connect ",
|
|
1802
|
+
vendor === "microsoft" ? "Outlook" : "Gmail"
|
|
1803
|
+
]
|
|
1804
|
+
},
|
|
1805
|
+
vendor
|
|
1806
|
+
)) }),
|
|
1807
|
+
accounts.map((account) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1808
|
+
"div",
|
|
1809
|
+
{
|
|
1810
|
+
className: "mb-2 flex items-center justify-between gap-2 rounded border p-3 text-sm",
|
|
1811
|
+
children: [
|
|
1812
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1813
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { children: account.email }),
|
|
1814
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground", children: account.display_name })
|
|
1815
|
+
] }),
|
|
1816
|
+
account.profile_id ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1817
|
+
ui.Button,
|
|
1818
|
+
{
|
|
1819
|
+
variant: "ghost",
|
|
1820
|
+
disabled: disconnect.isPending || offline,
|
|
1821
|
+
onClick: () => disconnect.mutate(account.id, { onError: (err) => setError(err.message) }),
|
|
1822
|
+
children: "Disconnect"
|
|
1823
|
+
}
|
|
1824
|
+
) : account.provider !== "native" ? authorizeOAuth && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1825
|
+
ui.Button,
|
|
1826
|
+
{
|
|
1827
|
+
variant: "ghost",
|
|
1828
|
+
disabled: offline,
|
|
1829
|
+
onClick: () => void oauth(account.provider),
|
|
1830
|
+
children: "Reconnect"
|
|
1831
|
+
}
|
|
1832
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Native inbox" })
|
|
1833
|
+
]
|
|
1834
|
+
},
|
|
1835
|
+
account.id
|
|
1836
|
+
)),
|
|
1837
|
+
policy.server_profiles.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1838
|
+
"form",
|
|
1839
|
+
{
|
|
1840
|
+
className: "mt-5 grid gap-3",
|
|
1841
|
+
onSubmit: (event) => {
|
|
1842
|
+
event.preventDefault();
|
|
1843
|
+
setError("");
|
|
1844
|
+
connect.mutate(
|
|
1845
|
+
{ profileId, email, username, password },
|
|
1846
|
+
{
|
|
1847
|
+
onSuccess: () => {
|
|
1848
|
+
setPassword("");
|
|
1849
|
+
onClose();
|
|
1850
|
+
},
|
|
1851
|
+
onError: (err) => setError(err.message)
|
|
1852
|
+
}
|
|
1853
|
+
);
|
|
1854
|
+
},
|
|
1855
|
+
children: [
|
|
1856
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "grid gap-1 text-sm", children: [
|
|
1857
|
+
"Mail server",
|
|
1858
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1859
|
+
"select",
|
|
1860
|
+
{
|
|
1861
|
+
"aria-label": "Mail server",
|
|
1862
|
+
className: "rounded border bg-background p-2",
|
|
1863
|
+
value: profileId,
|
|
1864
|
+
onChange: (e) => setProfileId(e.target.value),
|
|
1865
|
+
children: policy.server_profiles.map((profile) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: profile.id, children: profile.name }, profile.id))
|
|
1866
|
+
}
|
|
1867
|
+
)
|
|
1868
|
+
] }),
|
|
1869
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "grid gap-1 text-sm", children: [
|
|
1870
|
+
"Email address",
|
|
1871
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1872
|
+
"input",
|
|
1873
|
+
{
|
|
1874
|
+
required: true,
|
|
1875
|
+
type: "email",
|
|
1876
|
+
autoComplete: "email",
|
|
1877
|
+
className: "rounded border bg-background p-2",
|
|
1878
|
+
value: email,
|
|
1879
|
+
onChange: (e) => setEmail(e.target.value)
|
|
1880
|
+
}
|
|
1881
|
+
)
|
|
1882
|
+
] }),
|
|
1883
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "grid gap-1 text-sm", children: [
|
|
1884
|
+
"Username",
|
|
1885
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1886
|
+
"input",
|
|
1887
|
+
{
|
|
1888
|
+
placeholder: "Same as email address",
|
|
1889
|
+
autoComplete: "username",
|
|
1890
|
+
className: "rounded border bg-background p-2",
|
|
1891
|
+
value: username,
|
|
1892
|
+
onChange: (e) => setUsername(e.target.value)
|
|
1893
|
+
}
|
|
1894
|
+
)
|
|
1895
|
+
] }),
|
|
1896
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "grid gap-1 text-sm", children: [
|
|
1897
|
+
"Password or app password",
|
|
1898
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1899
|
+
"input",
|
|
1900
|
+
{
|
|
1901
|
+
required: true,
|
|
1902
|
+
type: "password",
|
|
1903
|
+
autoComplete: "current-password",
|
|
1904
|
+
className: "rounded border bg-background p-2",
|
|
1905
|
+
value: password,
|
|
1906
|
+
onChange: (e) => setPassword(e.target.value)
|
|
1907
|
+
}
|
|
1908
|
+
)
|
|
1909
|
+
] }),
|
|
1910
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", disabled: connect.isPending || offline, children: connect.isPending ? "Connecting\u2026" : "Connect mailbox" })
|
|
1911
|
+
]
|
|
1912
|
+
}
|
|
1913
|
+
),
|
|
1914
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-3 text-sm text-destructive", children: error }),
|
|
1915
|
+
accounts.length > 0 && settings
|
|
1916
|
+
] });
|
|
1917
|
+
if (embedded) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-2xl", children: content });
|
|
1918
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1919
|
+
ui.Dialog,
|
|
1920
|
+
{
|
|
1921
|
+
open: true,
|
|
1922
|
+
onOpenChange: (open) => {
|
|
1923
|
+
if (!open) onClose();
|
|
1924
|
+
},
|
|
1925
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { className: "max-h-[90dvh] max-w-lg overflow-auto", children: [
|
|
1926
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogTitle, { children: "Mail accounts" }),
|
|
1927
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { children: "Choose your email address or connect an external mailbox." }),
|
|
1928
|
+
content
|
|
1929
|
+
] })
|
|
1930
|
+
}
|
|
1931
|
+
);
|
|
1932
|
+
}
|
|
1933
|
+
var MailBodyEditor = react.lazy(
|
|
1934
|
+
() => import('../MailBodyEditor-D7MGJMLH.cjs').catch(() => ({
|
|
1935
|
+
default: chunk3R6XBYL7_cjs.PlainMailBodyEditor
|
|
1936
|
+
}))
|
|
1937
|
+
);
|
|
1938
|
+
function MailComposerForm({
|
|
1939
|
+
account,
|
|
1940
|
+
initial,
|
|
1941
|
+
maxBytes,
|
|
1942
|
+
ready,
|
|
1943
|
+
drafts,
|
|
1944
|
+
onClose,
|
|
1945
|
+
onOpenDraft,
|
|
1946
|
+
onChange,
|
|
1947
|
+
embedded = false,
|
|
1948
|
+
closeRequestRef,
|
|
1949
|
+
localDraftId: initialLocalDraftId,
|
|
1950
|
+
offline,
|
|
1951
|
+
documents,
|
|
1952
|
+
notify: notify3
|
|
1953
|
+
}) {
|
|
1954
|
+
const { client } = react$1.useMailClient();
|
|
1955
|
+
const [to, setTo] = react.useState(initial.to.map((r) => r.email).join("; "));
|
|
1956
|
+
const [cc, setCc] = react.useState(initial.cc.map((r) => r.email).join("; "));
|
|
1957
|
+
const [showCc, setShowCc] = react.useState(initial.cc.length > 0);
|
|
1958
|
+
const [showBcc, setShowBcc] = react.useState(initial.bcc.length > 0);
|
|
1959
|
+
const [bcc, setBcc] = react.useState(initial.bcc.map((r) => r.email).join("; "));
|
|
1960
|
+
const [subject, setSubject] = react.useState(initial.subject);
|
|
1961
|
+
const [text, setText] = react.useState(initial.text);
|
|
1962
|
+
const [html, setHtml] = react.useState(initial.html);
|
|
1963
|
+
const [attachments, setAttachments] = react.useState(initial.attachments);
|
|
1964
|
+
const [draftId, setDraftId] = react.useState(initial.draft_id);
|
|
1965
|
+
const [error, setError] = react.useState("");
|
|
1966
|
+
const [dirty, setDirty] = react.useState(false);
|
|
1967
|
+
const [attaching, setAttaching] = react.useState(false);
|
|
1968
|
+
const [saved, setSaved] = react.useState(false);
|
|
1969
|
+
const isOnline = react$1.useMailOnline();
|
|
1970
|
+
const [localDraftId, setLocalDraftId] = react.useState(initialLocalDraftId);
|
|
1971
|
+
const [savedLocally, setSavedLocally] = react.useState(false);
|
|
1972
|
+
const [secure, setSecure] = react.useState(initial.secure_delivery ?? false);
|
|
1973
|
+
const securePayload = react.useRef(null);
|
|
1974
|
+
const requestId = react.useRef(crypto.randomUUID());
|
|
1975
|
+
const attemptedPayload = react.useRef(null);
|
|
1976
|
+
const fileInput = react.useRef(null);
|
|
1977
|
+
const sameSubjectDraft = react.useMemo(() => {
|
|
1978
|
+
const key = subject.trim().toLowerCase();
|
|
1979
|
+
return key ? drafts.find((d) => d.id !== draftId && d.subject.trim().toLowerCase() === key) : void 0;
|
|
1980
|
+
}, [drafts, draftId, subject]);
|
|
1981
|
+
const body = () => ({
|
|
1982
|
+
...initial,
|
|
1983
|
+
to: chunk3R6XBYL7_cjs.parseMailRecipients(to),
|
|
1984
|
+
cc: chunk3R6XBYL7_cjs.parseMailRecipients(cc),
|
|
1985
|
+
bcc: chunk3R6XBYL7_cjs.parseMailRecipients(bcc),
|
|
1986
|
+
subject,
|
|
1987
|
+
text,
|
|
1988
|
+
html,
|
|
1989
|
+
attachments,
|
|
1990
|
+
draft_id: draftId,
|
|
1991
|
+
secure_delivery: secure
|
|
1992
|
+
});
|
|
1993
|
+
const saveOnDevice = async (compose) => {
|
|
1994
|
+
const draft = await offline.saveDraft(account.id, compose, localDraftId);
|
|
1995
|
+
setLocalDraftId(draft.id);
|
|
1996
|
+
};
|
|
1997
|
+
const save = react$1.useSaveMailDraft(
|
|
1998
|
+
offline && { keep: saveOnDevice, isNetworkFailure: offline.isNetworkFailure }
|
|
1999
|
+
);
|
|
2000
|
+
const queueInOutbox = async (compose) => {
|
|
2001
|
+
await offline.queueSend({
|
|
2002
|
+
account,
|
|
2003
|
+
compose,
|
|
2004
|
+
requestId: requestId.current,
|
|
2005
|
+
secure,
|
|
2006
|
+
securePayload: securePayload.current ?? void 0
|
|
2007
|
+
});
|
|
2008
|
+
if (localDraftId) await offline.deleteDraft(localDraftId);
|
|
2009
|
+
};
|
|
2010
|
+
const send = react$1.useSendMail(
|
|
2011
|
+
offline && { keep: queueInOutbox, isNetworkFailure: offline.isNetworkFailure }
|
|
2012
|
+
);
|
|
2013
|
+
const saveDraft = () => save.mutate(
|
|
2014
|
+
{ accountId: account.id, compose: body() },
|
|
2015
|
+
{
|
|
2016
|
+
onSuccess: (result) => {
|
|
2017
|
+
setSaved(true);
|
|
2018
|
+
setDirty(false);
|
|
2019
|
+
if ("onDevice" in result) {
|
|
2020
|
+
setSavedLocally(true);
|
|
2021
|
+
return;
|
|
2022
|
+
}
|
|
2023
|
+
setSavedLocally(false);
|
|
2024
|
+
setDraftId(result.id);
|
|
2025
|
+
if (localDraftId) {
|
|
2026
|
+
void offline?.deleteDraft(localDraftId);
|
|
2027
|
+
setLocalDraftId(void 0);
|
|
2028
|
+
}
|
|
2029
|
+
},
|
|
2030
|
+
onError: (err) => setError(err.message)
|
|
2031
|
+
}
|
|
2032
|
+
);
|
|
2033
|
+
const sendMessage = () => {
|
|
2034
|
+
let value = attemptedPayload.current;
|
|
2035
|
+
if (value === null) {
|
|
2036
|
+
value = body();
|
|
2037
|
+
const recipients = [...value.to, ...value.cc, ...value.bcc];
|
|
2038
|
+
const problem = !recipients.length || recipients.length > 100 ? "Enter between 1 and 100 recipients" : recipients.some((r) => !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(r.email)) ? "Check the recipient email addresses" : value.attachments.reduce((total, a) => total + a.size, 0) > maxBytes ? "Attachments exceed the email size limit" : null;
|
|
2039
|
+
if (problem) return setError(problem);
|
|
2040
|
+
if (!(offline && !isOnline)) attemptedPayload.current = value;
|
|
2041
|
+
}
|
|
2042
|
+
const sending = account;
|
|
2043
|
+
send.mutate(
|
|
2044
|
+
{
|
|
2045
|
+
accountId: account.id,
|
|
2046
|
+
compose: value,
|
|
2047
|
+
requestId: requestId.current,
|
|
2048
|
+
// Secure delivery prepares its encrypted payload once.
|
|
2049
|
+
secure: secure ? async () => {
|
|
2050
|
+
if (sending?.provider !== "native" || !client.prepareSecureMail)
|
|
2051
|
+
throw new Error("Choose your native inbox to send securely");
|
|
2052
|
+
securePayload.current ??= await client.prepareSecureMail(
|
|
2053
|
+
value,
|
|
2054
|
+
sending,
|
|
2055
|
+
requestId.current
|
|
2056
|
+
);
|
|
2057
|
+
return securePayload.current;
|
|
2058
|
+
} : void 0
|
|
2059
|
+
},
|
|
2060
|
+
{
|
|
2061
|
+
onSuccess: (result) => {
|
|
2062
|
+
if (result && typeof result === "object" && "onDevice" in result) {
|
|
2063
|
+
notify3("Saved to your Outbox", "info", {
|
|
2064
|
+
description: "It will be sent automatically when you're back online."
|
|
2065
|
+
});
|
|
2066
|
+
onClose();
|
|
2067
|
+
return;
|
|
2068
|
+
}
|
|
2069
|
+
notify3("Email queued for delivery", "success");
|
|
2070
|
+
if (localDraftId) void offline?.deleteDraft(localDraftId);
|
|
2071
|
+
onClose();
|
|
2072
|
+
},
|
|
2073
|
+
onError: (err) => setError(err.message)
|
|
2074
|
+
}
|
|
2075
|
+
);
|
|
2076
|
+
};
|
|
2077
|
+
const busy = attaching || save.isPending || send.isPending;
|
|
2078
|
+
const locked = busy || attemptedPayload.current !== null;
|
|
2079
|
+
const addFiles = async (files) => {
|
|
2080
|
+
if (!files) return;
|
|
2081
|
+
const selected = Array.from(files);
|
|
2082
|
+
if (attachments.reduce((n, a) => n + a.size, 0) + selected.reduce((n, f) => n + f.size, 0) > maxBytes) {
|
|
2083
|
+
setError(`Attachments must total less than ${Math.round(maxBytes / 1024 / 1024)} MB`);
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
setAttaching(true);
|
|
2087
|
+
try {
|
|
2088
|
+
const added = await Promise.all(selected.map(react$1.fileAttachment));
|
|
2089
|
+
setAttachments((previous) => [...previous, ...added]);
|
|
2090
|
+
setSaved(false);
|
|
2091
|
+
setDirty(true);
|
|
2092
|
+
} catch (err) {
|
|
2093
|
+
setError(err instanceof Error ? err.message : "Could not attach files");
|
|
2094
|
+
} finally {
|
|
2095
|
+
setAttaching(false);
|
|
2096
|
+
}
|
|
2097
|
+
};
|
|
2098
|
+
const addDocument = async (documentId) => {
|
|
2099
|
+
if (!documents) return;
|
|
2100
|
+
const used = attachments.reduce((n, a) => n + a.size, 0);
|
|
2101
|
+
setError("");
|
|
2102
|
+
setAttaching(true);
|
|
2103
|
+
try {
|
|
2104
|
+
const added = await documents.toAttachment(documentId, maxBytes - used);
|
|
2105
|
+
setAttachments((previous) => [...previous, added]);
|
|
2106
|
+
setSaved(false);
|
|
2107
|
+
setDirty(true);
|
|
2108
|
+
} catch (err) {
|
|
2109
|
+
setError(err instanceof Error ? err.message : "Could not attach the document");
|
|
2110
|
+
} finally {
|
|
2111
|
+
setAttaching(false);
|
|
2112
|
+
}
|
|
2113
|
+
};
|
|
2114
|
+
const close = () => {
|
|
2115
|
+
if (busy) return;
|
|
2116
|
+
if (!saved && (dirty || !draftId) && (text || subject || to || cc || bcc || attachments.length) && !window.confirm("Close this message without saving your latest changes?"))
|
|
2117
|
+
return;
|
|
2118
|
+
onClose();
|
|
2119
|
+
};
|
|
2120
|
+
react.useEffect(() => {
|
|
2121
|
+
if (closeRequestRef) closeRequestRef.current = close;
|
|
2122
|
+
});
|
|
2123
|
+
react.useEffect(() => {
|
|
2124
|
+
onChange?.(body());
|
|
2125
|
+
}, [to, cc, bcc, subject, text, html, attachments, draftId, secure]);
|
|
2126
|
+
const form = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2127
|
+
"form",
|
|
2128
|
+
{
|
|
2129
|
+
onKeyDown: (event) => {
|
|
2130
|
+
if (event.key !== "Enter") return;
|
|
2131
|
+
if (event.ctrlKey || event.metaKey) {
|
|
2132
|
+
event.preventDefault();
|
|
2133
|
+
if (ready && !busy) event.currentTarget.requestSubmit();
|
|
2134
|
+
} else if (event.target instanceof HTMLInputElement) {
|
|
2135
|
+
event.preventDefault();
|
|
2136
|
+
}
|
|
2137
|
+
},
|
|
2138
|
+
onSubmit: (e) => {
|
|
2139
|
+
e.preventDefault();
|
|
2140
|
+
setError("");
|
|
2141
|
+
sendMessage();
|
|
2142
|
+
},
|
|
2143
|
+
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",
|
|
2144
|
+
children: [
|
|
2145
|
+
!embedded && /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex items-center justify-between border-b px-5 py-3", children: [
|
|
2146
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "font-semibold", children: "New message" }),
|
|
2147
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2148
|
+
ui.Button,
|
|
2149
|
+
{
|
|
2150
|
+
type: "button",
|
|
2151
|
+
variant: "ghost",
|
|
2152
|
+
"aria-label": "Close message",
|
|
2153
|
+
disabled: busy,
|
|
2154
|
+
onClick: close,
|
|
2155
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
|
|
2156
|
+
}
|
|
2157
|
+
)
|
|
2158
|
+
] }),
|
|
2159
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-0 flex-1 overflow-auto px-5 py-3", children: [
|
|
2160
|
+
sameSubjectDraft && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2161
|
+
"div",
|
|
2162
|
+
{
|
|
2163
|
+
role: "status",
|
|
2164
|
+
className: "mb-3 flex items-center justify-between gap-3 rounded-md bg-muted/40 px-3 py-2 text-xs text-muted-foreground",
|
|
2165
|
+
children: [
|
|
2166
|
+
"A draft with this subject is already in Drafts.",
|
|
2167
|
+
onOpenDraft && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2168
|
+
ui.Button,
|
|
2169
|
+
{
|
|
2170
|
+
type: "button",
|
|
2171
|
+
variant: "ghost",
|
|
2172
|
+
className: "h-7 shrink-0 text-xs",
|
|
2173
|
+
onClick: () => onOpenDraft(sameSubjectDraft.id),
|
|
2174
|
+
children: "Open draft"
|
|
2175
|
+
}
|
|
2176
|
+
)
|
|
2177
|
+
]
|
|
2178
|
+
}
|
|
2179
|
+
),
|
|
2180
|
+
/* @__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: [
|
|
2181
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-14 shrink-0", children: "From" }),
|
|
2182
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-muted/50 px-2 py-1 text-foreground", children: account?.email ?? "Connect a mailbox to send" })
|
|
2183
|
+
] }),
|
|
2184
|
+
[
|
|
2185
|
+
["To", to, setTo],
|
|
2186
|
+
["Cc", cc, setCc],
|
|
2187
|
+
["Bcc", bcc, setBcc]
|
|
2188
|
+
].filter(
|
|
2189
|
+
([label]) => label === "To" || label === "Cc" && showCc || label === "Bcc" && showBcc
|
|
2190
|
+
).map(([label, value, setter]) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2191
|
+
"label",
|
|
2192
|
+
{
|
|
2193
|
+
className: "flex items-center gap-3 border-b border-border/60 py-2.5 text-sm focus-within:border-primary",
|
|
2194
|
+
children: [
|
|
2195
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-14 shrink-0 text-xs text-muted-foreground", children: label }),
|
|
2196
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2197
|
+
"input",
|
|
2198
|
+
{
|
|
2199
|
+
"aria-label": label,
|
|
2200
|
+
required: label === "To" && !cc && !bcc,
|
|
2201
|
+
disabled: locked,
|
|
2202
|
+
className: "min-w-0 flex-1 bg-transparent outline-none",
|
|
2203
|
+
value,
|
|
2204
|
+
placeholder: label === "To" ? "Add recipients" : "",
|
|
2205
|
+
onChange: (e) => {
|
|
2206
|
+
setter(e.target.value);
|
|
2207
|
+
setSaved(false);
|
|
2208
|
+
setDirty(true);
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
),
|
|
2212
|
+
label === "To" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 gap-2", children: [
|
|
2213
|
+
!showCc && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2214
|
+
"button",
|
|
2215
|
+
{
|
|
2216
|
+
type: "button",
|
|
2217
|
+
disabled: locked,
|
|
2218
|
+
className: "text-xs text-muted-foreground hover:text-primary",
|
|
2219
|
+
onClick: () => setShowCc(true),
|
|
2220
|
+
children: "Cc"
|
|
2221
|
+
}
|
|
2222
|
+
),
|
|
2223
|
+
!showBcc && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2224
|
+
"button",
|
|
2225
|
+
{
|
|
2226
|
+
type: "button",
|
|
2227
|
+
disabled: locked,
|
|
2228
|
+
className: "text-xs text-muted-foreground hover:text-primary",
|
|
2229
|
+
onClick: () => setShowBcc(true),
|
|
2230
|
+
children: "Bcc"
|
|
2231
|
+
}
|
|
2232
|
+
)
|
|
2233
|
+
] })
|
|
2234
|
+
]
|
|
2235
|
+
},
|
|
2236
|
+
label
|
|
2237
|
+
)),
|
|
2238
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-3 border-b border-border/60 py-2.5 text-sm focus-within:border-primary", children: [
|
|
2239
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-14 shrink-0 text-xs text-muted-foreground", children: "Subject" }),
|
|
2240
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2241
|
+
"input",
|
|
2242
|
+
{
|
|
2243
|
+
"aria-label": "Subject",
|
|
2244
|
+
placeholder: "Add a subject",
|
|
2245
|
+
disabled: locked,
|
|
2246
|
+
className: "min-w-0 flex-1 bg-transparent outline-none",
|
|
2247
|
+
value: subject,
|
|
2248
|
+
onChange: (e) => {
|
|
2249
|
+
setSubject(e.target.value);
|
|
2250
|
+
setSaved(false);
|
|
2251
|
+
setDirty(true);
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
)
|
|
2255
|
+
] }),
|
|
2256
|
+
/* @__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(
|
|
2257
|
+
MailBodyEditor,
|
|
2258
|
+
{
|
|
2259
|
+
text,
|
|
2260
|
+
html,
|
|
2261
|
+
disabled: locked,
|
|
2262
|
+
onChange: (nextText, nextHtml) => {
|
|
2263
|
+
setText(nextText);
|
|
2264
|
+
setHtml(nextHtml);
|
|
2265
|
+
setSaved(false);
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
) }),
|
|
2269
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: attachments.map((attachment, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2270
|
+
"span",
|
|
2271
|
+
{
|
|
2272
|
+
className: "flex items-center gap-2 rounded-md border border-border/70 bg-muted/30 px-3 py-2 text-xs",
|
|
2273
|
+
children: [
|
|
2274
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "size-3" }),
|
|
2275
|
+
attachment.name,
|
|
2276
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2277
|
+
"button",
|
|
2278
|
+
{
|
|
2279
|
+
type: "button",
|
|
2280
|
+
disabled: locked,
|
|
2281
|
+
"aria-label": `Remove ${attachment.name}`,
|
|
2282
|
+
onClick: () => {
|
|
2283
|
+
setAttachments((a) => a.filter((_, i) => i !== index));
|
|
2284
|
+
setSaved(false);
|
|
2285
|
+
setDirty(true);
|
|
2286
|
+
},
|
|
2287
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3" })
|
|
2288
|
+
}
|
|
2289
|
+
)
|
|
2290
|
+
]
|
|
2291
|
+
},
|
|
2292
|
+
`${attachment.name}-${index}`
|
|
2293
|
+
)) }),
|
|
2294
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-3 text-sm text-destructive", children: error })
|
|
2295
|
+
] }),
|
|
2296
|
+
/* @__PURE__ */ jsxRuntime.jsxs("footer", { className: "flex flex-wrap items-center gap-1 border-t border-border/60 bg-muted/20 px-4 py-2 [&_button]:h-8 [&_button]:text-xs", children: [
|
|
2297
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2298
|
+
ui.Button,
|
|
2299
|
+
{
|
|
2300
|
+
type: "button",
|
|
2301
|
+
variant: "outline",
|
|
2302
|
+
disabled: !ready || locked,
|
|
2303
|
+
onClick: () => {
|
|
2304
|
+
setError("");
|
|
2305
|
+
saveDraft();
|
|
2306
|
+
},
|
|
2307
|
+
children: save.isPending ? "Saving\u2026" : "Save draft"
|
|
2308
|
+
}
|
|
2309
|
+
),
|
|
2310
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2311
|
+
ui.Button,
|
|
2312
|
+
{
|
|
2313
|
+
type: "button",
|
|
2314
|
+
variant: "ghost",
|
|
2315
|
+
disabled: locked,
|
|
2316
|
+
onClick: () => fileInput.current?.click(),
|
|
2317
|
+
children: [
|
|
2318
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "mr-2 size-4" }),
|
|
2319
|
+
"Attach"
|
|
2320
|
+
]
|
|
2321
|
+
}
|
|
2322
|
+
),
|
|
2323
|
+
documents && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2324
|
+
chunk3R6XBYL7_cjs.MailDocumentPicker,
|
|
2325
|
+
{
|
|
2326
|
+
documents: documents.documents,
|
|
2327
|
+
disabled: locked,
|
|
2328
|
+
onAttach: (doc) => void addDocument(doc.id)
|
|
2329
|
+
}
|
|
2330
|
+
),
|
|
2331
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2332
|
+
"input",
|
|
2333
|
+
{
|
|
2334
|
+
ref: fileInput,
|
|
2335
|
+
type: "file",
|
|
2336
|
+
multiple: true,
|
|
2337
|
+
hidden: true,
|
|
2338
|
+
onChange: (e) => {
|
|
2339
|
+
void addFiles(e.target.files);
|
|
2340
|
+
e.target.value = "";
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
),
|
|
2344
|
+
saved && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-nowrap text-xs text-muted-foreground", children: savedLocally ? "Saved on this device \xB7 syncs to Drafts when online" : "Saved to Drafts" }),
|
|
2345
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
|
|
2346
|
+
account?.provider === "native" && client.prepareSecureMail && /* @__PURE__ */ jsxRuntime.jsxs(ui.Tooltip, { children: [
|
|
2347
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.TooltipTrigger, { asChild: true, showWithText: true, children: /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex h-8 shrink-0 cursor-pointer items-center gap-1.5 rounded border border-border/70 px-2 text-xs text-primary", children: [
|
|
2348
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2349
|
+
"input",
|
|
2350
|
+
{
|
|
2351
|
+
type: "checkbox",
|
|
2352
|
+
className: "size-3.5 accent-primary",
|
|
2353
|
+
checked: secure,
|
|
2354
|
+
disabled: locked,
|
|
2355
|
+
onChange: (e) => setSecure(e.target.checked)
|
|
2356
|
+
}
|
|
2357
|
+
),
|
|
2358
|
+
"Secure"
|
|
2359
|
+
] }) }),
|
|
2360
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.TooltipContent, { side: "top", children: "The recipient will receive a secure link to access the message through the platform." })
|
|
2361
|
+
] }),
|
|
2362
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2363
|
+
ui.Button,
|
|
2364
|
+
{
|
|
2365
|
+
type: "submit",
|
|
2366
|
+
className: "h-8 rounded bg-primary px-4 text-primary-foreground shadow-none hover:bg-primary/90",
|
|
2367
|
+
disabled: !ready || busy,
|
|
2368
|
+
children: [
|
|
2369
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "mr-2 size-4" }),
|
|
2370
|
+
send.isPending ? "Sending\u2026" : attemptedPayload.current ? "Check send result" : "Send"
|
|
2371
|
+
]
|
|
2372
|
+
}
|
|
2373
|
+
)
|
|
2374
|
+
] }),
|
|
2375
|
+
offline && !isOnline && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2376
|
+
"p",
|
|
2377
|
+
{
|
|
2378
|
+
className: "w-full text-[11px] text-muted-foreground",
|
|
2379
|
+
"data-testid": "compose-offline-hint",
|
|
2380
|
+
children: "You're offline. Send puts this message in your Outbox; it goes out when you reconnect."
|
|
2381
|
+
}
|
|
2382
|
+
)
|
|
2383
|
+
] })
|
|
2384
|
+
]
|
|
2385
|
+
}
|
|
2386
|
+
);
|
|
2387
|
+
if (embedded)
|
|
2388
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "dialog", "aria-label": "Compose email", className: "h-full min-h-0", children: form });
|
|
2389
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2390
|
+
ui.Dialog,
|
|
2391
|
+
{
|
|
2392
|
+
open: true,
|
|
2393
|
+
onOpenChange: (open) => {
|
|
2394
|
+
if (!open && !busy) close();
|
|
2395
|
+
},
|
|
2396
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { className: "max-h-[95dvh] max-w-3xl overflow-auto p-0", children: [
|
|
2397
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogTitle, { className: "sr-only", children: "Compose email" }),
|
|
2398
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { className: "sr-only", children: "Write a message and attach files." }),
|
|
2399
|
+
form
|
|
2400
|
+
] })
|
|
2401
|
+
}
|
|
2402
|
+
);
|
|
2403
|
+
}
|
|
2404
|
+
var defaultMailNotify = (message, variant, options) => {
|
|
2405
|
+
react$1.notify[variant](message, options);
|
|
2406
|
+
};
|
|
2407
|
+
function resolveMailbox(accounts, mailbox) {
|
|
2408
|
+
if (!accounts) return void 0;
|
|
2409
|
+
if (mailbox === "native") return accounts.find((a) => a.provider === "native");
|
|
2410
|
+
return mailbox ? accounts.find((a) => a.id === mailbox) : void 0;
|
|
2411
|
+
}
|
|
2412
|
+
var DEFAULT_MAX_BYTES = 15 * 1024 * 1024;
|
|
2413
|
+
function ConnectedMailComposer({
|
|
2414
|
+
draftId,
|
|
2415
|
+
initial,
|
|
2416
|
+
account: accountProp,
|
|
2417
|
+
mailbox = "native",
|
|
2418
|
+
maxBytes: maxBytesProp,
|
|
2419
|
+
ready: readyProp,
|
|
2420
|
+
drafts: draftsProp,
|
|
2421
|
+
notify: notify3 = defaultMailNotify,
|
|
2422
|
+
offline,
|
|
2423
|
+
...rest
|
|
2424
|
+
}) {
|
|
2425
|
+
const { client } = react$1.useMailClient();
|
|
2426
|
+
const isOnline = react$1.useMailOnline();
|
|
2427
|
+
const policy = react$1.useMailPolicy();
|
|
2428
|
+
const accounts = react$1.useMailAccounts({ enabled: !accountProp && !!policy.data?.enabled });
|
|
2429
|
+
const account = accountProp ?? resolveMailbox(accounts.data, mailbox);
|
|
2430
|
+
const unlock = react$1.useMailUnlock(readyProp === void 0 ? account : void 0);
|
|
2431
|
+
const ready = readyProp ?? (!!account && (!!unlock.data || !isOnline));
|
|
2432
|
+
const folders = react$1.useMailFolders(account, { enabled: !draftsProp && ready });
|
|
2433
|
+
const draftsFolderId = folders.data?.find((f) => f.role === "drafts")?.id;
|
|
2434
|
+
const draftsList = react$1.useMailMessages(account, draftsFolderId, "", null, {
|
|
2435
|
+
enabled: !draftsProp && ready
|
|
2436
|
+
});
|
|
2437
|
+
const draft = react$1.useMailDraftCompose(
|
|
2438
|
+
account,
|
|
2439
|
+
draftId,
|
|
2440
|
+
async (from, id) => {
|
|
2441
|
+
const message = await client.getMessage(from, id);
|
|
2442
|
+
return chunk3R6XBYL7_cjs.draftMailCompose(
|
|
2443
|
+
message,
|
|
2444
|
+
await hydrateMailAttachments(client, from, message.id, message.attachments, {
|
|
2445
|
+
isOnline,
|
|
2446
|
+
offline
|
|
2447
|
+
})
|
|
2448
|
+
);
|
|
2449
|
+
},
|
|
2450
|
+
{ enabled: !initial && ready }
|
|
2451
|
+
);
|
|
2452
|
+
const start = react.useMemo(
|
|
2453
|
+
() => initial ?? (draftId ? draft.data : chunk3R6XBYL7_cjs.emptyMailCompose()),
|
|
2454
|
+
[initial, draftId, draft.data]
|
|
2455
|
+
);
|
|
2456
|
+
if (!start)
|
|
2457
|
+
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" });
|
|
2458
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2459
|
+
MailComposerForm,
|
|
2460
|
+
{
|
|
2461
|
+
account,
|
|
2462
|
+
initial: start,
|
|
2463
|
+
maxBytes: maxBytesProp ?? policy.data?.max_attachment_bytes ?? DEFAULT_MAX_BYTES,
|
|
2464
|
+
ready,
|
|
2465
|
+
drafts: draftsProp ?? draftsList.data?.messages ?? [],
|
|
2466
|
+
notify: notify3,
|
|
2467
|
+
offline,
|
|
2468
|
+
...rest
|
|
2469
|
+
},
|
|
2470
|
+
`${account?.id}-${draftId ?? ""}`
|
|
2471
|
+
);
|
|
2472
|
+
}
|
|
2473
|
+
function ConnectedMailSetup({
|
|
2474
|
+
policy,
|
|
2475
|
+
user,
|
|
2476
|
+
productName,
|
|
2477
|
+
onClaimed,
|
|
2478
|
+
onConnectExisting
|
|
2479
|
+
}) {
|
|
2480
|
+
const isOnline = react$1.useMailOnline();
|
|
2481
|
+
const [alias, setAlias] = react.useState(() => react$1.defaultMailAlias(user));
|
|
2482
|
+
const [error, setError] = react.useState("");
|
|
2483
|
+
const claim = react$1.useClaimNativeAlias(onClaimed);
|
|
2484
|
+
const hasExternal = policy.oauth_providers.length > 0 || policy.server_profiles.length > 0;
|
|
2485
|
+
const onClaimError = (err) => {
|
|
2486
|
+
if (!react$1.isAliasTakenError(err)) return setError(err.message);
|
|
2487
|
+
const suggestion = react$1.nextAliasSuggestion(alias);
|
|
2488
|
+
setAlias(suggestion);
|
|
2489
|
+
setError(react$1.aliasTakenMessage(alias, suggestion, policy.native_domain));
|
|
2490
|
+
};
|
|
2491
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2492
|
+
"div",
|
|
2493
|
+
{
|
|
2494
|
+
"data-testid": "mail-setup",
|
|
2495
|
+
className: "mx-auto flex max-w-xl flex-col items-center gap-6 px-6 py-16 text-center",
|
|
2496
|
+
children: [
|
|
2497
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mail, { className: "size-10 text-muted-foreground", "aria-hidden": true }),
|
|
2498
|
+
policy.native_enabled ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2499
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2500
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-xl font-semibold text-foreground", children: [
|
|
2501
|
+
"Set up your ",
|
|
2502
|
+
productName ? `${productName} ` : "",
|
|
2503
|
+
"email"
|
|
2504
|
+
] }),
|
|
2505
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Confirm your address and you are ready to go: you can send and receive email as" })
|
|
2506
|
+
] }),
|
|
2507
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2508
|
+
"form",
|
|
2509
|
+
{
|
|
2510
|
+
className: "flex w-full flex-col items-center gap-4",
|
|
2511
|
+
onSubmit: (e) => {
|
|
2512
|
+
e.preventDefault();
|
|
2513
|
+
setError("");
|
|
2514
|
+
claim.mutate(alias, { onError: onClaimError });
|
|
2515
|
+
},
|
|
2516
|
+
children: [
|
|
2517
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center justify-center gap-2 text-base", children: [
|
|
2518
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2519
|
+
ui.Input,
|
|
2520
|
+
{
|
|
2521
|
+
"aria-label": "Email alias",
|
|
2522
|
+
required: true,
|
|
2523
|
+
pattern: "[a-z0-9][a-z0-9._\\-]{0,62}",
|
|
2524
|
+
autoFocus: true,
|
|
2525
|
+
className: "max-w-60 text-right",
|
|
2526
|
+
value: alias,
|
|
2527
|
+
onChange: (e) => setAlias(e.target.value.toLowerCase())
|
|
2528
|
+
}
|
|
2529
|
+
),
|
|
2530
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-foreground", children: [
|
|
2531
|
+
"@",
|
|
2532
|
+
policy.native_domain
|
|
2533
|
+
] })
|
|
2534
|
+
] }),
|
|
2535
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2536
|
+
ui.Button,
|
|
2537
|
+
{
|
|
2538
|
+
type: "submit",
|
|
2539
|
+
disabled: claim.isPending || !alias || !isOnline,
|
|
2540
|
+
title: isOnline ? void 0 : "Available when you are back online",
|
|
2541
|
+
children: claim.isPending ? "Setting up\u2026" : "Confirm"
|
|
2542
|
+
}
|
|
2543
|
+
)
|
|
2544
|
+
]
|
|
2545
|
+
}
|
|
2546
|
+
)
|
|
2547
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2548
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-semibold text-foreground", children: "Connect your email" }),
|
|
2549
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-2 text-sm text-muted-foreground", children: [
|
|
2550
|
+
"Connect an existing account to read and send email",
|
|
2551
|
+
" ",
|
|
2552
|
+
productName ? `from ${productName}` : "here",
|
|
2553
|
+
"."
|
|
2554
|
+
] })
|
|
2555
|
+
] }),
|
|
2556
|
+
hasExternal && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2557
|
+
ui.Button,
|
|
2558
|
+
{
|
|
2559
|
+
variant: policy.native_enabled ? "ghost" : "default",
|
|
2560
|
+
onClick: onConnectExisting,
|
|
2561
|
+
className: policy.native_enabled ? "text-muted-foreground" : void 0,
|
|
2562
|
+
children: policy.native_enabled ? "Connect an existing email account instead" : "Connect an email account"
|
|
2563
|
+
}
|
|
2564
|
+
),
|
|
2565
|
+
!policy.native_enabled && !hasExternal && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Mail is not set up for this deployment yet. Ask your administrator." }),
|
|
2566
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-sm text-destructive", children: error })
|
|
2567
|
+
]
|
|
2568
|
+
}
|
|
2569
|
+
);
|
|
2570
|
+
}
|
|
2571
|
+
var NO_DRAFTS = [];
|
|
2572
|
+
var NO_OUTBOX = [];
|
|
2573
|
+
var LOCAL_DRAFT_PREFIX = "local-draft:";
|
|
2574
|
+
var OFFLINE_FOLDERS = [
|
|
2575
|
+
{ id: "device:drafts", name: "Drafts", role: "drafts", unread: 0 }
|
|
2576
|
+
];
|
|
2577
|
+
function localDraftRow(draft) {
|
|
2578
|
+
return {
|
|
2579
|
+
id: LOCAL_DRAFT_PREFIX + draft.id,
|
|
2580
|
+
subject: draft.compose.subject,
|
|
2581
|
+
sender: [],
|
|
2582
|
+
to: draft.compose.to,
|
|
2583
|
+
cc: draft.compose.cc,
|
|
2584
|
+
bcc: draft.compose.bcc,
|
|
2585
|
+
received_at: new Date(draft.updatedAt).toISOString(),
|
|
2586
|
+
preview: draft.error ? `Saved on this device only: ${draft.error}` : "Saved on this device \xB7 syncs to Drafts when online",
|
|
2587
|
+
unread: false,
|
|
2588
|
+
text: "",
|
|
2589
|
+
references: [],
|
|
2590
|
+
attachments: draft.compose.attachments.map((a) => ({ ...a, content_base64: null }))
|
|
2591
|
+
};
|
|
2592
|
+
}
|
|
2593
|
+
function applyQuickFilters(messages, filters) {
|
|
2594
|
+
const included = [...filters].filter(([, s]) => s === "include").map(([k]) => k);
|
|
2595
|
+
const excluded = [...filters].filter(([, s]) => s === "exclude").map(([k]) => k);
|
|
2596
|
+
if (!included.length && !excluded.length) return messages;
|
|
2597
|
+
return messages.filter((m) => {
|
|
2598
|
+
const has = {
|
|
2599
|
+
unread: m.unread,
|
|
2600
|
+
attachments: m.attachments.length > 0,
|
|
2601
|
+
secure: !!m.secure_delivery
|
|
2602
|
+
};
|
|
2603
|
+
if (excluded.some((k) => has[k])) return false;
|
|
2604
|
+
return !included.length || included.some((k) => has[k]);
|
|
2605
|
+
});
|
|
2606
|
+
}
|
|
2607
|
+
function SidePanel({ isOpen, title, onClose, children }) {
|
|
2608
|
+
if (!isOpen) return null;
|
|
2609
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2610
|
+
"aside",
|
|
2611
|
+
{
|
|
2612
|
+
"aria-label": title,
|
|
2613
|
+
className: "flex min-h-0 w-full max-w-2xl shrink-0 flex-col border-l border-border bg-background",
|
|
2614
|
+
children: [
|
|
2615
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex items-center justify-between gap-2 border-b px-3 py-2", children: [
|
|
2616
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "truncate text-sm font-semibold", children: title }),
|
|
2617
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2618
|
+
ui.Button,
|
|
2619
|
+
{
|
|
2620
|
+
variant: "ghost",
|
|
2621
|
+
size: "sm",
|
|
2622
|
+
"aria-label": "Close",
|
|
2623
|
+
"data-testid": "close-mail-viewer",
|
|
2624
|
+
onClick: onClose,
|
|
2625
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-4" })
|
|
2626
|
+
}
|
|
2627
|
+
)
|
|
2628
|
+
] }),
|
|
2629
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-0 flex-1", children })
|
|
2630
|
+
]
|
|
2631
|
+
}
|
|
2632
|
+
);
|
|
2633
|
+
}
|
|
2634
|
+
function ConnectedMailbox({
|
|
2635
|
+
mailbox,
|
|
2636
|
+
draftId,
|
|
2637
|
+
onDraftOpened,
|
|
2638
|
+
folder: requestedFolder,
|
|
2639
|
+
onFolderOpened,
|
|
2640
|
+
composeAttachments,
|
|
2641
|
+
onComposeOpened,
|
|
2642
|
+
onOpenDocument,
|
|
2643
|
+
user,
|
|
2644
|
+
productName,
|
|
2645
|
+
oauthReturnPath,
|
|
2646
|
+
personLabel,
|
|
2647
|
+
offline,
|
|
2648
|
+
documents,
|
|
2649
|
+
saveToWorkspace,
|
|
2650
|
+
renderInvite,
|
|
2651
|
+
renderPanel = SidePanel,
|
|
2652
|
+
onViewerOpenChange,
|
|
2653
|
+
gridState,
|
|
2654
|
+
onGridStateChange,
|
|
2655
|
+
initialMessageId = null,
|
|
2656
|
+
notify: notify3 = defaultMailNotify
|
|
2657
|
+
}) {
|
|
2658
|
+
const cache = react$1.useMailCache();
|
|
2659
|
+
const { client } = react$1.useMailClient();
|
|
2660
|
+
const [savingToWorkspace, setSavingToWorkspace] = react.useState(false);
|
|
2661
|
+
const [savePending, setSavePending] = react.useState(false);
|
|
2662
|
+
const [saveWorkspaceId, setSaveWorkspaceId] = react.useState("");
|
|
2663
|
+
const { data: policy, error: policyError } = react$1.useMailPolicy();
|
|
2664
|
+
const isOnline = react$1.useMailOnline();
|
|
2665
|
+
const accounts = react$1.useMailAccounts({ enabled: !!policy?.enabled });
|
|
2666
|
+
const [accountId, setAccountId] = react.useState("");
|
|
2667
|
+
const account = accounts.data?.find((a) => a.id === accountId) ?? resolveMailbox(accounts.data, mailbox) ?? accounts.data?.[0];
|
|
2668
|
+
const unlock = react$1.useMailUnlock(account);
|
|
2669
|
+
const [folder, setFolder] = react.useState("inbox");
|
|
2670
|
+
const [folderMenuOpen, setFolderMenuOpen] = react.useState(false);
|
|
2671
|
+
const [filterMenuOpen, setFilterMenuOpen] = react.useState(false);
|
|
2672
|
+
const [query, setQuery] = react.useState("");
|
|
2673
|
+
const [mailFilters, setMailFilters] = react.useState(/* @__PURE__ */ new Map());
|
|
2674
|
+
const [cursor, setCursor] = react.useState(null);
|
|
2675
|
+
const [selected, setSelected] = react.useState(initialMessageId);
|
|
2676
|
+
const [compose, setCompose] = react.useState(null);
|
|
2677
|
+
const [composeLocalDraftId, setComposeLocalDraftId] = react.useState();
|
|
2678
|
+
const [composeSession, setComposeSession] = react.useState(0);
|
|
2679
|
+
const openCompose = (value, localDraftId) => {
|
|
2680
|
+
setComposeSession((n) => n + 1);
|
|
2681
|
+
setComposeLocalDraftId(localDraftId);
|
|
2682
|
+
setCompose(value);
|
|
2683
|
+
};
|
|
2684
|
+
const composeClose = react.useRef(null);
|
|
2685
|
+
react.useEffect(() => {
|
|
2686
|
+
onViewerOpenChange?.(!!selected || !!compose);
|
|
2687
|
+
}, [selected, compose, onViewerOpenChange]);
|
|
2688
|
+
react.useEffect(() => () => onViewerOpenChange?.(false), [onViewerOpenChange]);
|
|
2689
|
+
const [settings, setSettings] = react.useState(false);
|
|
2690
|
+
const [justCreated, setJustCreated] = react.useState(false);
|
|
2691
|
+
const [actionError, setActionError] = react.useState("");
|
|
2692
|
+
const ready = !!account && (!!unlock.data || !isOnline);
|
|
2693
|
+
react.useEffect(() => {
|
|
2694
|
+
if (unlock.data) void cache.refreshFolders();
|
|
2695
|
+
}, [unlock.data, cache]);
|
|
2696
|
+
const folders = react$1.useMailFolders(account, { enabled: ready });
|
|
2697
|
+
const outbox = offline?.useOutbox() ?? NO_OUTBOX;
|
|
2698
|
+
const outboxRole = offline?.outboxRole;
|
|
2699
|
+
const waitingInOutbox = outbox.filter(
|
|
2700
|
+
(item) => item.account.id === account?.id && item.status !== "sent"
|
|
2701
|
+
).length;
|
|
2702
|
+
const folderList = react.useMemo(() => {
|
|
2703
|
+
const base = folders.data ?? (offline && !isOnline && folders.error ? OFFLINE_FOLDERS : void 0);
|
|
2704
|
+
if (!base || !outboxRole) return base;
|
|
2705
|
+
const withCount = (f) => f.role === outboxRole ? { ...f, unread: f.unread + waitingInOutbox } : f;
|
|
2706
|
+
return base.some((f) => f.role === outboxRole) ? base.map(withCount) : [...base, withCount({ id: "device:outbox", name: "Outbox", role: outboxRole, unread: 0 })];
|
|
2707
|
+
}, [folders.data, folders.error, isOnline, waitingInOutbox, offline, outboxRole]);
|
|
2708
|
+
const folderId = folderList?.find((f) => f.role === folder || f.id === folder)?.id ?? folderList?.[0]?.id;
|
|
2709
|
+
const folderRole = folderList?.find((f) => f.id === folderId)?.role ?? folder;
|
|
2710
|
+
const deviceFolder = !!folderId?.startsWith("device:");
|
|
2711
|
+
const list = react$1.useMailMessages(account, folderId, query, cursor, {
|
|
2712
|
+
enabled: ready && !deviceFolder,
|
|
2713
|
+
refetchInterval: 6e4
|
|
2714
|
+
});
|
|
2715
|
+
const localDrafts = offline?.useLocalDrafts(account?.id) ?? NO_DRAFTS;
|
|
2716
|
+
const draftsFolderId = folders.data?.find((f) => f.role === "drafts")?.id;
|
|
2717
|
+
const drafts = react$1.useMailMessages(account, draftsFolderId, "", null, {
|
|
2718
|
+
enabled: ready && !!compose
|
|
2719
|
+
});
|
|
2720
|
+
const loadedMessages = react.useMemo(() => {
|
|
2721
|
+
if (folderRole !== "drafts") return list.data?.messages;
|
|
2722
|
+
const words = query.toLowerCase();
|
|
2723
|
+
const mine = localDrafts.map(localDraftRow).filter(
|
|
2724
|
+
(m) => !words || `${m.subject} ${m.to.map((r) => r.email).join(" ")}`.toLowerCase().includes(words)
|
|
2725
|
+
);
|
|
2726
|
+
return [...mine, ...list.data?.messages ?? []];
|
|
2727
|
+
}, [folderRole, list.data, localDrafts, query]);
|
|
2728
|
+
const filteredMessages = react.useMemo(
|
|
2729
|
+
() => applyQuickFilters(loadedMessages ?? [], mailFilters),
|
|
2730
|
+
[loadedMessages, mailFilters]
|
|
2731
|
+
);
|
|
2732
|
+
const mailFilterOptions = react.useMemo(
|
|
2733
|
+
() => [
|
|
2734
|
+
{
|
|
2735
|
+
id: "unread",
|
|
2736
|
+
label: "Unread",
|
|
2737
|
+
count: (loadedMessages ?? []).filter((m) => m.unread).length
|
|
2738
|
+
},
|
|
2739
|
+
{
|
|
2740
|
+
id: "attachments",
|
|
2741
|
+
label: "Has attachments",
|
|
2742
|
+
count: (loadedMessages ?? []).filter((m) => m.attachments.length > 0).length
|
|
2743
|
+
},
|
|
2744
|
+
{
|
|
2745
|
+
id: "secure",
|
|
2746
|
+
label: "Secure delivery",
|
|
2747
|
+
count: (loadedMessages ?? []).filter((m) => m.secure_delivery).length
|
|
2748
|
+
}
|
|
2749
|
+
],
|
|
2750
|
+
[loadedMessages]
|
|
2751
|
+
);
|
|
2752
|
+
const hasActiveFilters = !!query || [...mailFilters.values()].some(Boolean);
|
|
2753
|
+
const detail = react$1.useMailMessage(account, selected, { enabled: ready && !compose });
|
|
2754
|
+
const message = detail.data;
|
|
2755
|
+
react.useEffect(() => {
|
|
2756
|
+
if (!composeAttachments?.length) return;
|
|
2757
|
+
openCompose({ ...chunk3R6XBYL7_cjs.emptyMailCompose(), attachments: composeAttachments });
|
|
2758
|
+
onComposeOpened?.();
|
|
2759
|
+
}, [composeAttachments]);
|
|
2760
|
+
react.useEffect(() => {
|
|
2761
|
+
if (!requestedFolder) return;
|
|
2762
|
+
setFolder(requestedFolder);
|
|
2763
|
+
setCursor(null);
|
|
2764
|
+
setSelected(null);
|
|
2765
|
+
onFolderOpened?.();
|
|
2766
|
+
}, [requestedFolder]);
|
|
2767
|
+
const [pendingDraft, setPendingDraft] = react.useState(null);
|
|
2768
|
+
react.useEffect(() => {
|
|
2769
|
+
if (!draftId) return;
|
|
2770
|
+
composeClose.current?.();
|
|
2771
|
+
setFolder("drafts");
|
|
2772
|
+
setCursor(null);
|
|
2773
|
+
setSelected(null);
|
|
2774
|
+
setPendingDraft(draftId);
|
|
2775
|
+
onDraftOpened?.();
|
|
2776
|
+
}, [draftId]);
|
|
2777
|
+
react.useEffect(() => {
|
|
2778
|
+
if (!pendingDraft || !accounts.data) return;
|
|
2779
|
+
const native = accounts.data.find((a) => a.provider === "native");
|
|
2780
|
+
if (native) setAccountId(native.id);
|
|
2781
|
+
setSelected(pendingDraft);
|
|
2782
|
+
setPendingDraft(null);
|
|
2783
|
+
}, [pendingDraft, accounts.data]);
|
|
2784
|
+
react.useEffect(() => {
|
|
2785
|
+
const chosen = resolveMailbox(accounts.data, mailbox);
|
|
2786
|
+
if (!chosen) return;
|
|
2787
|
+
setAccountId(chosen.id);
|
|
2788
|
+
}, [mailbox, !!accounts.data]);
|
|
2789
|
+
const patch = (messageId, body) => react$1.mailJson(
|
|
2790
|
+
client.fetch,
|
|
2791
|
+
`${react$1.accountPath(account.id)}/messages/${encodeURIComponent(messageId)}`,
|
|
2792
|
+
{
|
|
2793
|
+
method: "PATCH",
|
|
2794
|
+
body: JSON.stringify(body)
|
|
2795
|
+
}
|
|
2796
|
+
);
|
|
2797
|
+
const update = async (body) => {
|
|
2798
|
+
if (!selected || !account || !isOnline) return;
|
|
2799
|
+
try {
|
|
2800
|
+
await patch(selected, body);
|
|
2801
|
+
await cache.refreshAll();
|
|
2802
|
+
if (body.folder_id || body.action) setSelected(null);
|
|
2803
|
+
} catch (e) {
|
|
2804
|
+
setActionError(e instanceof Error ? e.message : "Could not update message");
|
|
2805
|
+
}
|
|
2806
|
+
};
|
|
2807
|
+
const download = async (path, name) => {
|
|
2808
|
+
try {
|
|
2809
|
+
const response = await client.fetch(path);
|
|
2810
|
+
saveFile(await response.blob(), name);
|
|
2811
|
+
} catch (e) {
|
|
2812
|
+
setActionError(e instanceof Error ? e.message : "Download failed");
|
|
2813
|
+
}
|
|
2814
|
+
};
|
|
2815
|
+
const downloadAttachment = async (a) => {
|
|
2816
|
+
if (!message || !account) return;
|
|
2817
|
+
if (isOnline) {
|
|
2818
|
+
await download(attachmentPath(account.id, message.id, a.id), a.name);
|
|
2819
|
+
return;
|
|
2820
|
+
}
|
|
2821
|
+
const file = await offline?.loadAttachment(account.id, message.id, a);
|
|
2822
|
+
if (!file) {
|
|
2823
|
+
setActionError(`${a.name} isn't saved on this device. Open it when you're back online.`);
|
|
2824
|
+
return;
|
|
2825
|
+
}
|
|
2826
|
+
saveFile(file, a.name);
|
|
2827
|
+
};
|
|
2828
|
+
const saveEmail = async () => {
|
|
2829
|
+
if (!message || !account || !saveWorkspaceId || !saveToWorkspace) return;
|
|
2830
|
+
setSavePending(true);
|
|
2831
|
+
try {
|
|
2832
|
+
const response = await client.fetch(
|
|
2833
|
+
`${react$1.accountPath(account.id)}/messages/${message.id}/original`
|
|
2834
|
+
);
|
|
2835
|
+
const fileName = `${message.subject.replace(/[^a-zA-Z0-9 ._-]/g, "").slice(0, 80) || "email"}.eml`;
|
|
2836
|
+
const workspaceId = saveWorkspaceId;
|
|
2837
|
+
const documentId = await saveToWorkspace.save(
|
|
2838
|
+
workspaceId,
|
|
2839
|
+
new File([await response.blob()], fileName, { type: "message/rfc822" })
|
|
2840
|
+
);
|
|
2841
|
+
setSavingToWorkspace(false);
|
|
2842
|
+
notify3(
|
|
2843
|
+
"Email saved to workspace",
|
|
2844
|
+
"success",
|
|
2845
|
+
documentId && onOpenDocument ? { action: { label: "Open", onClick: () => onOpenDocument(documentId, workspaceId) } } : void 0
|
|
2846
|
+
);
|
|
2847
|
+
} catch (e) {
|
|
2848
|
+
setActionError(e instanceof Error ? e.message : "Could not save email to workspace");
|
|
2849
|
+
} finally {
|
|
2850
|
+
setSavePending(false);
|
|
2851
|
+
}
|
|
2852
|
+
};
|
|
2853
|
+
const hydrate = (attachments) => message && account ? hydrateMailAttachments(client, account, message.id, attachments, { isOnline, offline }) : Promise.resolve([]);
|
|
2854
|
+
const editDraft = async () => {
|
|
2855
|
+
if (!message) return;
|
|
2856
|
+
try {
|
|
2857
|
+
openCompose(chunk3R6XBYL7_cjs.draftMailCompose(message, await hydrate(message.attachments)));
|
|
2858
|
+
} catch (e) {
|
|
2859
|
+
setActionError(e instanceof Error ? e.message : "Could not load draft attachments");
|
|
2860
|
+
}
|
|
2861
|
+
};
|
|
2862
|
+
const reply = async (forward = false, all = false) => {
|
|
2863
|
+
if (!message || !account) return;
|
|
2864
|
+
try {
|
|
2865
|
+
const attachments = forward ? await hydrate(message.attachments) : [];
|
|
2866
|
+
openCompose(chunk3R6XBYL7_cjs.replyMailCompose(message, { account, folderRole, forward, all, attachments }));
|
|
2867
|
+
} catch (e) {
|
|
2868
|
+
setActionError(e instanceof Error ? e.message : "Could not prepare forwarded attachments");
|
|
2869
|
+
}
|
|
2870
|
+
};
|
|
2871
|
+
const failures = [policyError, accounts.error, unlock.error, folders.error, list.error];
|
|
2872
|
+
const offlineNotice = failures.find((e) => e instanceof react$1.MailOfflineUnavailableError)?.message;
|
|
2873
|
+
const error = actionError || failures.find((e) => e && !(e instanceof react$1.MailOfflineUnavailableError))?.message || (detail.error instanceof react$1.MailOfflineUnavailableError ? void 0 : detail.error?.message);
|
|
2874
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex h-full min-h-0 flex-col bg-background", "aria-label": "Mail", children: [
|
|
2875
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "sticky top-0 z-10 bg-background", children: [
|
|
2876
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2877
|
+
chunk7RGLTF76_cjs.TabHeader,
|
|
2878
|
+
{
|
|
2879
|
+
testId: "mail-tab-header",
|
|
2880
|
+
tabs: [
|
|
2881
|
+
{
|
|
2882
|
+
id: "mail",
|
|
2883
|
+
// Icon + count only, like the Files, Facts and Threads headers.
|
|
2884
|
+
label: "",
|
|
2885
|
+
count: filteredMessages.length,
|
|
2886
|
+
countIcon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mail, { className: "size-3.5" }),
|
|
2887
|
+
countPlacement: "leading",
|
|
2888
|
+
presentation: "count",
|
|
2889
|
+
hasActiveFilters,
|
|
2890
|
+
testId: "mail-tab"
|
|
2891
|
+
}
|
|
2892
|
+
],
|
|
2893
|
+
activeTabId: "mail",
|
|
2894
|
+
onTabChange: () => {
|
|
2895
|
+
},
|
|
2896
|
+
compactBreakpoint: 360,
|
|
2897
|
+
firstTabContent: account ? /* @__PURE__ */ jsxRuntime.jsxs(chunkO4YPVYPO_cjs.FilesFilterBar, { children: [
|
|
2898
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2899
|
+
chunk2EI7NCUA_cjs.FilterInput,
|
|
2900
|
+
{
|
|
2901
|
+
value: query,
|
|
2902
|
+
onChange: (q) => {
|
|
2903
|
+
setQuery(q);
|
|
2904
|
+
setCursor(null);
|
|
2905
|
+
},
|
|
2906
|
+
hideFieldPicker: true,
|
|
2907
|
+
fields: ["text"],
|
|
2908
|
+
onFieldsChange: () => {
|
|
2909
|
+
},
|
|
2910
|
+
ariaLabel: "Filter mail",
|
|
2911
|
+
labels: { placeholder: "Filter..." },
|
|
2912
|
+
testIds: { root: "mail-search", input: "mail-filter-input" },
|
|
2913
|
+
className: "min-w-28 flex-1 sm:max-w-72",
|
|
2914
|
+
filter: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2915
|
+
chunkAFSOUS5X_cjs.TriStateFilterMenu,
|
|
2916
|
+
{
|
|
2917
|
+
testId: "mail-bar-filter-button",
|
|
2918
|
+
open: filterMenuOpen,
|
|
2919
|
+
onOpenChange: setFilterMenuOpen,
|
|
2920
|
+
filterStates: mailFilters,
|
|
2921
|
+
onFiltersChange: setMailFilters,
|
|
2922
|
+
options: mailFilterOptions,
|
|
2923
|
+
groups: [{ label: "Messages", options: ["unread", "attachments", "secure"] }],
|
|
2924
|
+
renderChevron: true,
|
|
2925
|
+
disableHoverOpen: true,
|
|
2926
|
+
triggerClassName: "inline-flex items-center gap-0.5 h-6 rounded px-1 text-muted-foreground hover:bg-foreground/10 cursor-pointer transition-colors pointer-coarse:h-11! pointer-coarse:min-w-11 pointer-coarse:justify-center"
|
|
2927
|
+
}
|
|
2928
|
+
)
|
|
2929
|
+
}
|
|
2930
|
+
),
|
|
2931
|
+
folderList && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2932
|
+
chunkO4YPVYPO_cjs.FolderFilterButton,
|
|
2933
|
+
{
|
|
2934
|
+
label: folderList.find((f) => f.id === folderId)?.name ?? "Folders",
|
|
2935
|
+
isActive: false,
|
|
2936
|
+
open: folderMenuOpen,
|
|
2937
|
+
onOpenChange: setFolderMenuOpen,
|
|
2938
|
+
testId: "mail-folder-button",
|
|
2939
|
+
children: folderList.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2940
|
+
chunkO4YPVYPO_cjs.FolderPickerRow,
|
|
2941
|
+
{
|
|
2942
|
+
label: item.name,
|
|
2943
|
+
count: item.unread > 0 ? item.unread : void 0,
|
|
2944
|
+
depth: 0,
|
|
2945
|
+
isActive: item.id === folderId,
|
|
2946
|
+
onClick: () => {
|
|
2947
|
+
setFolder(item.id);
|
|
2948
|
+
setCursor(null);
|
|
2949
|
+
setSelected(null);
|
|
2950
|
+
setFolderMenuOpen(false);
|
|
2951
|
+
}
|
|
2952
|
+
},
|
|
2953
|
+
item.id
|
|
2954
|
+
))
|
|
2955
|
+
}
|
|
2956
|
+
) })
|
|
2957
|
+
] }) : void 0,
|
|
2958
|
+
rightContent: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1", children: [
|
|
2959
|
+
account && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2960
|
+
ui.Button,
|
|
2961
|
+
{
|
|
2962
|
+
size: "sm",
|
|
2963
|
+
variant: "ghost",
|
|
2964
|
+
"aria-label": "Mail settings",
|
|
2965
|
+
"data-testid": "mail-settings-button",
|
|
2966
|
+
onClick: () => setSettings(true),
|
|
2967
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { className: "size-4" })
|
|
2968
|
+
}
|
|
2969
|
+
),
|
|
2970
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2971
|
+
ui.Button,
|
|
2972
|
+
{
|
|
2973
|
+
size: "sm",
|
|
2974
|
+
disabled: !ready || !!compose,
|
|
2975
|
+
onClick: () => openCompose(chunk3R6XBYL7_cjs.emptyMailCompose()),
|
|
2976
|
+
children: [
|
|
2977
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "mr-1.5 size-4" }),
|
|
2978
|
+
"Email"
|
|
2979
|
+
]
|
|
2980
|
+
}
|
|
2981
|
+
)
|
|
2982
|
+
] })
|
|
2983
|
+
}
|
|
2984
|
+
),
|
|
2985
|
+
(accounts.data?.length ?? 0) > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 px-3 py-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2986
|
+
"select",
|
|
2987
|
+
{
|
|
2988
|
+
"aria-label": "Mail account",
|
|
2989
|
+
disabled: !!compose,
|
|
2990
|
+
className: "min-w-0 max-w-64 rounded border-0 bg-transparent px-2 py-1.5 text-xs text-muted-foreground",
|
|
2991
|
+
value: account?.id ?? "",
|
|
2992
|
+
onChange: (e) => {
|
|
2993
|
+
setAccountId(e.target.value);
|
|
2994
|
+
setFolder("inbox");
|
|
2995
|
+
setCursor(null);
|
|
2996
|
+
setSelected(null);
|
|
2997
|
+
},
|
|
2998
|
+
children: accounts.data?.map((a) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: a.id, children: a.email }, a.id))
|
|
2999
|
+
}
|
|
3000
|
+
) })
|
|
3001
|
+
] }),
|
|
3002
|
+
account && offline?.renderStatus?.(),
|
|
3003
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "border-b p-3 text-sm text-destructive", children: error }),
|
|
3004
|
+
!error && offlineNotice && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", className: "border-b p-3 text-sm text-muted-foreground", children: offlineNotice }),
|
|
3005
|
+
policy && !policy.enabled && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-6 text-muted-foreground", children: "Mail is not enabled on this deployment." }),
|
|
3006
|
+
policy?.enabled && accounts.isSuccess && !account && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3007
|
+
ConnectedMailSetup,
|
|
3008
|
+
{
|
|
3009
|
+
policy,
|
|
3010
|
+
user,
|
|
3011
|
+
productName,
|
|
3012
|
+
onClaimed: () => setJustCreated(true),
|
|
3013
|
+
onConnectExisting: () => setSettings(true)
|
|
3014
|
+
}
|
|
3015
|
+
),
|
|
3016
|
+
account && justCreated && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3017
|
+
"div",
|
|
3018
|
+
{
|
|
3019
|
+
role: "status",
|
|
3020
|
+
"data-testid": "mail-ready-banner",
|
|
3021
|
+
className: "flex items-start justify-between gap-3 border-b bg-accent/40 px-4 py-3 text-sm",
|
|
3022
|
+
children: [
|
|
3023
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
3024
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold", children: [
|
|
3025
|
+
"Your ",
|
|
3026
|
+
productName ? `${productName} ` : "",
|
|
3027
|
+
"email is ready to go."
|
|
3028
|
+
] }),
|
|
3029
|
+
" ",
|
|
3030
|
+
"You can send and receive email as ",
|
|
3031
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: account.email }),
|
|
3032
|
+
"."
|
|
3033
|
+
] }),
|
|
3034
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3035
|
+
"button",
|
|
3036
|
+
{
|
|
3037
|
+
type: "button",
|
|
3038
|
+
"aria-label": "Dismiss",
|
|
3039
|
+
className: "text-muted-foreground hover:text-foreground",
|
|
3040
|
+
onClick: () => setJustCreated(false),
|
|
3041
|
+
children: "\xD7"
|
|
3042
|
+
}
|
|
3043
|
+
)
|
|
3044
|
+
]
|
|
3045
|
+
}
|
|
3046
|
+
),
|
|
3047
|
+
account && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1", children: [
|
|
3048
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 w-full flex-col", children: [
|
|
3049
|
+
outboxRole && folderRole === outboxRole && offline?.renderOutbox({
|
|
3050
|
+
accountId: account.id,
|
|
3051
|
+
onEdit: (value) => openCompose({ ...value })
|
|
3052
|
+
}),
|
|
3053
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: deviceFolder ? "hidden" : "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3054
|
+
chunk3R6XBYL7_cjs.MailGrid,
|
|
3055
|
+
{
|
|
3056
|
+
messages: filteredMessages,
|
|
3057
|
+
loading: list.isPending && list.fetchStatus !== "idle",
|
|
3058
|
+
selected,
|
|
3059
|
+
outgoing: folderRole === "sent" || folderRole === "drafts" || folderRole === outboxRole,
|
|
3060
|
+
personLabel,
|
|
3061
|
+
gridState,
|
|
3062
|
+
onGridStateChange,
|
|
3063
|
+
onSelect: (id) => {
|
|
3064
|
+
if (id.startsWith(LOCAL_DRAFT_PREFIX)) {
|
|
3065
|
+
const draft = localDrafts.find((d) => LOCAL_DRAFT_PREFIX + d.id === id);
|
|
3066
|
+
if (draft) openCompose({ ...draft.compose }, draft.id);
|
|
3067
|
+
return;
|
|
3068
|
+
}
|
|
3069
|
+
setSelected(id);
|
|
3070
|
+
if (isOnline && list.data?.messages.find((m) => m.id === id)?.unread) {
|
|
3071
|
+
void patch(id, { unread: false }).then(() => cache.settleMessage(account.id, id)).catch((error2) => setActionError(error2.message));
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
) }),
|
|
3076
|
+
(cursor || list.data?.next_cursor) && /* @__PURE__ */ jsxRuntime.jsxs("footer", { className: "flex gap-2 p-2", children: [
|
|
3077
|
+
cursor && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "ghost", onClick: () => setCursor(null), children: "First page" }),
|
|
3078
|
+
list.data?.next_cursor && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "ghost", onClick: () => setCursor(list.data.next_cursor), children: "Next page" })
|
|
3079
|
+
] })
|
|
3080
|
+
] }),
|
|
3081
|
+
renderPanel({
|
|
3082
|
+
isOpen: !!selected || !!compose,
|
|
3083
|
+
title: compose ? "New message" : message?.subject || "Mail",
|
|
3084
|
+
onClose: () => {
|
|
3085
|
+
if (compose) composeClose.current?.();
|
|
3086
|
+
else setSelected(null);
|
|
3087
|
+
},
|
|
3088
|
+
children: compose ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3089
|
+
ConnectedMailComposer,
|
|
3090
|
+
{
|
|
3091
|
+
account,
|
|
3092
|
+
initial: compose,
|
|
3093
|
+
maxBytes: policy?.max_attachment_bytes ?? 15 * 1024 * 1024,
|
|
3094
|
+
ready,
|
|
3095
|
+
drafts: drafts.data?.messages ?? [],
|
|
3096
|
+
embedded: true,
|
|
3097
|
+
localDraftId: composeLocalDraftId,
|
|
3098
|
+
offline,
|
|
3099
|
+
documents,
|
|
3100
|
+
notify: notify3,
|
|
3101
|
+
onChange: setCompose,
|
|
3102
|
+
closeRequestRef: composeClose,
|
|
3103
|
+
onClose: () => {
|
|
3104
|
+
setCompose(null);
|
|
3105
|
+
if (compose.draft_id) setSelected(null);
|
|
3106
|
+
},
|
|
3107
|
+
onOpenDraft: (id) => {
|
|
3108
|
+
composeClose.current?.();
|
|
3109
|
+
setFolder("drafts");
|
|
3110
|
+
setCursor(null);
|
|
3111
|
+
setSelected(id);
|
|
3112
|
+
}
|
|
3113
|
+
},
|
|
3114
|
+
`${account?.id}-${composeSession}`
|
|
3115
|
+
) : message && selected ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3116
|
+
chunk3R6XBYL7_cjs.MailMessageView,
|
|
3117
|
+
{
|
|
3118
|
+
account,
|
|
3119
|
+
message,
|
|
3120
|
+
folderRole,
|
|
3121
|
+
folders: folders.data,
|
|
3122
|
+
isOnline,
|
|
3123
|
+
loading: detail.isFetching,
|
|
3124
|
+
uploadPending: savePending,
|
|
3125
|
+
personLabel,
|
|
3126
|
+
renderInvite: renderInvite && (() => renderInvite({
|
|
3127
|
+
accountId: account.id,
|
|
3128
|
+
messageId: message.id,
|
|
3129
|
+
attachments: message.attachments,
|
|
3130
|
+
isOnline
|
|
3131
|
+
})),
|
|
3132
|
+
onBack: () => setSelected(null),
|
|
3133
|
+
onEditDraft: () => void editDraft(),
|
|
3134
|
+
onReply: (forward, all) => void reply(forward, all),
|
|
3135
|
+
onUpdate: (body) => void update(body),
|
|
3136
|
+
onDownloadAttachment: (a) => void downloadAttachment(a),
|
|
3137
|
+
onDownloadOriginal: () => void download(
|
|
3138
|
+
`${react$1.accountPath(account.id)}/messages/${message.id}/original`,
|
|
3139
|
+
"original.eml"
|
|
3140
|
+
),
|
|
3141
|
+
onSaveToWorkspace: saveToWorkspace && (() => {
|
|
3142
|
+
setSaveWorkspaceId(
|
|
3143
|
+
saveToWorkspace.defaultWorkspaceId ?? saveToWorkspace.workspaces[0]?.id ?? ""
|
|
3144
|
+
);
|
|
3145
|
+
setSavingToWorkspace(true);
|
|
3146
|
+
})
|
|
3147
|
+
}
|
|
3148
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs("article", { className: "min-w-0 flex-1 overflow-auto p-4 sm:p-5", children: [
|
|
3149
|
+
selected && /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { className: "mb-3", variant: "ghost", onClick: () => setSelected(null), children: [
|
|
3150
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "mr-2 size-4" }),
|
|
3151
|
+
"Back"
|
|
3152
|
+
] }),
|
|
3153
|
+
detail.isFetching && selected && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "Loading message\u2026" }),
|
|
3154
|
+
detail.error instanceof react$1.MailOfflineUnavailableError && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", className: "text-sm text-muted-foreground", children: detail.error.message })
|
|
3155
|
+
] })
|
|
3156
|
+
})
|
|
3157
|
+
] }),
|
|
3158
|
+
saveToWorkspace && /* @__PURE__ */ jsxRuntime.jsx(ui.Dialog, { open: savingToWorkspace, onOpenChange: setSavingToWorkspace, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.DialogContent, { children: [
|
|
3159
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogTitle, { children: "Save email to workspace" }),
|
|
3160
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DialogDescription, { children: "Save a copy as an .eml file. Members with access to the file can read it." }),
|
|
3161
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3162
|
+
"select",
|
|
3163
|
+
{
|
|
3164
|
+
"aria-label": "Destination workspace",
|
|
3165
|
+
value: saveWorkspaceId,
|
|
3166
|
+
onChange: (e) => setSaveWorkspaceId(e.target.value),
|
|
3167
|
+
className: "rounded border bg-background p-2",
|
|
3168
|
+
children: [
|
|
3169
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Choose a workspace" }),
|
|
3170
|
+
saveToWorkspace.workspaces.map((w) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: w.id, children: w.name }, w.id))
|
|
3171
|
+
]
|
|
3172
|
+
}
|
|
3173
|
+
),
|
|
3174
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { disabled: !saveWorkspaceId || savePending, onClick: () => void saveEmail(), children: savePending ? "Saving\u2026" : "Save email" }),
|
|
3175
|
+
actionError && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", children: actionError })
|
|
3176
|
+
] }) }),
|
|
3177
|
+
settings && policy && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3178
|
+
ConnectedMailAccounts,
|
|
3179
|
+
{
|
|
3180
|
+
policy,
|
|
3181
|
+
accounts: accounts.data ?? [],
|
|
3182
|
+
user,
|
|
3183
|
+
oauthReturnPath,
|
|
3184
|
+
settings: offline?.renderSettings?.(),
|
|
3185
|
+
onClose: () => setSettings(false)
|
|
3186
|
+
}
|
|
3187
|
+
)
|
|
3188
|
+
] });
|
|
3189
|
+
}
|
|
1619
3190
|
function ActiveChat({ agentId, workspaceId }) {
|
|
1620
3191
|
const chat = react$1.useArbiChat({ agentId, workspaceId });
|
|
1621
3192
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1732,19 +3303,25 @@ exports.ConnectedAgentChatPanel = ConnectedAgentChatPanel;
|
|
|
1732
3303
|
exports.ConnectedDangerZone = ConnectedDangerZone;
|
|
1733
3304
|
exports.ConnectedIdentityVerification = ConnectedIdentityVerification;
|
|
1734
3305
|
exports.ConnectedLogoutDialog = ConnectedLogoutDialog;
|
|
3306
|
+
exports.ConnectedMailAccounts = ConnectedMailAccounts;
|
|
3307
|
+
exports.ConnectedMailComposer = ConnectedMailComposer;
|
|
3308
|
+
exports.ConnectedMailSetup = ConnectedMailSetup;
|
|
3309
|
+
exports.ConnectedMailbox = ConnectedMailbox;
|
|
1735
3310
|
exports.ConnectedNotificationPreferences = ConnectedNotificationPreferences;
|
|
1736
3311
|
exports.ConnectedProfileCard = ConnectedProfileCard;
|
|
1737
3312
|
exports.ConnectedRequireVerified = ConnectedRequireVerified;
|
|
1738
3313
|
exports.ConnectedSecuritySection = ConnectedSecuritySection;
|
|
1739
3314
|
exports.ConnectedSessionsRow = ConnectedSessionsRow;
|
|
1740
3315
|
exports.ConnectedSkillUpload = ConnectedSkillUpload;
|
|
1741
|
-
exports.
|
|
3316
|
+
exports.ConnectedTagTable = ConnectedTagTable;
|
|
1742
3317
|
exports.ConnectedTaskAccessRequest = ConnectedTaskAccessRequest;
|
|
1743
3318
|
exports.ConnectedWorkflowRunner = ConnectedWorkflowRunner;
|
|
1744
3319
|
exports.DEFAULT_CONNECTED_WORKFLOW_RUNNER_LABELS = DEFAULT_CONNECTED_WORKFLOW_RUNNER_LABELS;
|
|
1745
3320
|
exports.StreamedArtifact = StreamedArtifact;
|
|
1746
3321
|
exports.WorkflowRunThread = WorkflowRunThread;
|
|
3322
|
+
exports.defaultMailNotify = defaultMailNotify;
|
|
1747
3323
|
exports.defaultUnmetPasswordRequirement = defaultUnmetPasswordRequirement;
|
|
3324
|
+
exports.resolveMailbox = resolveMailbox;
|
|
1748
3325
|
exports.useConnectedDocxNotifications = useConnectedDocxNotifications;
|
|
1749
3326
|
exports.useConnectedShellWorkspaces = useConnectedShellWorkspaces;
|
|
1750
3327
|
exports.useConnectedWorkNotifications = useConnectedWorkNotifications;
|