@zaclinley/dsh-mailharbor 0.7.0 → 0.7.1
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/CHANGELOG.md +11 -0
- package/lib/client.js +146 -6
- package/lib/client.js.map +2 -2
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 841e14b: Add a mail to an existing project from the reader.
|
|
8
|
+
|
|
9
|
+
- The reader toolbar gains "加入项目": pick an existing project or create a new
|
|
10
|
+
one and the current mail is linked immediately.
|
|
11
|
+
- Multi-select ("选择") is available in server mode too, so several mails can
|
|
12
|
+
be added to a project from the live view.
|
|
13
|
+
|
|
3
14
|
## 0.7.0
|
|
4
15
|
|
|
5
16
|
### Minor Changes
|
package/lib/client.js
CHANGED
|
@@ -501,6 +501,12 @@ var PATHS = {
|
|
|
501
501
|
(0, import_react3.createElement)("path", { d: "M10 11v6M14 11v6" })
|
|
502
502
|
),
|
|
503
503
|
send: (0, import_react3.createElement)("path", { d: "m4 4 17 8-17 8 3.6-8z M7.6 12H21" }),
|
|
504
|
+
list: (0, import_react3.createElement)(
|
|
505
|
+
"g",
|
|
506
|
+
null,
|
|
507
|
+
(0, import_react3.createElement)("path", { d: "M8 6h12M8 12h12M8 18h12" }),
|
|
508
|
+
(0, import_react3.createElement)("path", { d: "M4 6h.01M4 12h.01M4 18h.01" })
|
|
509
|
+
),
|
|
504
510
|
folder: (0, import_react3.createElement)("path", {
|
|
505
511
|
d: "M3.5 6.5A1.5 1.5 0 0 1 5 5h4l2 2.5h8A1.5 1.5 0 0 1 20.5 9v8.5A1.5 1.5 0 0 1 19 19H5a1.5 1.5 0 0 1-1.5-1.5z"
|
|
506
512
|
}),
|
|
@@ -1928,6 +1934,7 @@ function Reader({
|
|
|
1928
1934
|
onReply,
|
|
1929
1935
|
onAiAction,
|
|
1930
1936
|
onExtractTasks,
|
|
1937
|
+
onAddToProject,
|
|
1931
1938
|
onClose
|
|
1932
1939
|
}) {
|
|
1933
1940
|
const [plain, setPlain] = (0, import_react8.useState)(false);
|
|
@@ -2036,6 +2043,12 @@ function Reader({
|
|
|
2036
2043
|
(0, import_react8.createElement)(Icon, { name: "checklist", size: 14 }),
|
|
2037
2044
|
"\u63D0\u53D6\u4EFB\u52A1"
|
|
2038
2045
|
),
|
|
2046
|
+
(0, import_react8.createElement)(
|
|
2047
|
+
"button",
|
|
2048
|
+
{ className: "ghost", onClick: onAddToProject },
|
|
2049
|
+
(0, import_react8.createElement)(Icon, { name: "folder", size: 14 }),
|
|
2050
|
+
"\u52A0\u5165\u9879\u76EE"
|
|
2051
|
+
),
|
|
2039
2052
|
(0, import_react8.createElement)("span", { className: "spacer" }),
|
|
2040
2053
|
html ? (0, import_react8.createElement)(
|
|
2041
2054
|
"button",
|
|
@@ -2192,6 +2205,11 @@ function MailPanel() {
|
|
|
2192
2205
|
const [extraction, setExtraction] = (0, import_react9.useState)(null);
|
|
2193
2206
|
const [extractBusy, setExtractBusy] = (0, import_react9.useState)(false);
|
|
2194
2207
|
const [aiInfo, setAiInfo] = (0, import_react9.useState)(null);
|
|
2208
|
+
const [projectPicker, setProjectPicker] = (0, import_react9.useState)(null);
|
|
2209
|
+
const [pickerProjects, setPickerProjects] = (0, import_react9.useState)([]);
|
|
2210
|
+
const [pickerTarget, setPickerTarget] = (0, import_react9.useState)("");
|
|
2211
|
+
const [pickerNewName, setPickerNewName] = (0, import_react9.useState)("");
|
|
2212
|
+
const [pickerBusy, setPickerBusy] = (0, import_react9.useState)(false);
|
|
2195
2213
|
const [aiSearching, setAiSearching] = (0, import_react9.useState)(false);
|
|
2196
2214
|
const [aiRequest, setAiRequest] = (0, import_react9.useState)(null);
|
|
2197
2215
|
const [tick, setTick] = (0, import_react9.useState)(0);
|
|
@@ -2261,6 +2279,66 @@ function MailPanel() {
|
|
|
2261
2279
|
setAiSearching(false);
|
|
2262
2280
|
}
|
|
2263
2281
|
};
|
|
2282
|
+
const openProjectPicker = () => {
|
|
2283
|
+
if (selected === null) return;
|
|
2284
|
+
const key = keyOf(selected);
|
|
2285
|
+
if (!key.startsWith("mid:") && !key.startsWith("local:")) {
|
|
2286
|
+
setError("\u8FD9\u5C01\u90AE\u4EF6\u7F3A\u5C11 Message-ID\uFF0C\u65E0\u6CD5\u5173\u8054\u5230\u9879\u76EE");
|
|
2287
|
+
return;
|
|
2288
|
+
}
|
|
2289
|
+
setProjectPicker({
|
|
2290
|
+
accountId: selected.accountId,
|
|
2291
|
+
key,
|
|
2292
|
+
subject: selected.subject,
|
|
2293
|
+
date: selected.date
|
|
2294
|
+
});
|
|
2295
|
+
setPickerNewName(selected.subject.replace(/^(re|fwd):\s*/i, "").slice(0, 80));
|
|
2296
|
+
setPickerTarget("");
|
|
2297
|
+
void api.projects().then((list) => {
|
|
2298
|
+
setPickerProjects(list.items);
|
|
2299
|
+
setPickerTarget(list.items[0]?.id ?? "");
|
|
2300
|
+
}).catch((caught) => setError(errorText5(caught)));
|
|
2301
|
+
};
|
|
2302
|
+
const saveProjectPick = async () => {
|
|
2303
|
+
if (projectPicker === null) return;
|
|
2304
|
+
setPickerBusy(true);
|
|
2305
|
+
setError("");
|
|
2306
|
+
try {
|
|
2307
|
+
if (pickerTarget !== "") {
|
|
2308
|
+
await api.addProjectMessage(pickerTarget, {
|
|
2309
|
+
accountId: projectPicker.accountId,
|
|
2310
|
+
key: projectPicker.key,
|
|
2311
|
+
subject: projectPicker.subject,
|
|
2312
|
+
date: projectPicker.date
|
|
2313
|
+
});
|
|
2314
|
+
notice("\u5DF2\u52A0\u5165\u9879\u76EE");
|
|
2315
|
+
} else {
|
|
2316
|
+
const name = pickerNewName.trim();
|
|
2317
|
+
if (name === "") throw new Error("\u5148\u9009\u62E9\u4E00\u4E2A\u9879\u76EE\uFF0C\u6216\u586B\u5199\u65B0\u9879\u76EE\u540D\u79F0");
|
|
2318
|
+
const settings = await api.settings();
|
|
2319
|
+
const created = await api.createProject({
|
|
2320
|
+
accountId: projectPicker.accountId,
|
|
2321
|
+
name,
|
|
2322
|
+
root: settings.projects.root,
|
|
2323
|
+
conversation: `\uFF08\u4ECE\u90AE\u4EF6\u52A0\u5165\uFF09
|
|
2324
|
+
|
|
2325
|
+
${projectPicker.subject}`,
|
|
2326
|
+
message: {
|
|
2327
|
+
key: projectPicker.key,
|
|
2328
|
+
subject: projectPicker.subject,
|
|
2329
|
+
date: projectPicker.date
|
|
2330
|
+
}
|
|
2331
|
+
});
|
|
2332
|
+
notice(`\u9879\u76EE\u5DF2\u521B\u5EFA\uFF1A${created.project.path}`);
|
|
2333
|
+
}
|
|
2334
|
+
setProjectPicker(null);
|
|
2335
|
+
setTick((value) => value + 1);
|
|
2336
|
+
} catch (caught) {
|
|
2337
|
+
setError(errorText5(caught));
|
|
2338
|
+
} finally {
|
|
2339
|
+
setPickerBusy(false);
|
|
2340
|
+
}
|
|
2341
|
+
};
|
|
2264
2342
|
const toggleSide = () => {
|
|
2265
2343
|
setSideOpen((open) => {
|
|
2266
2344
|
try {
|
|
@@ -2286,8 +2364,11 @@ function MailPanel() {
|
|
|
2286
2364
|
setError("\u5148\u521B\u5EFA\u4E00\u4E2A\u9879\u76EE");
|
|
2287
2365
|
return;
|
|
2288
2366
|
}
|
|
2289
|
-
const chosen = items.filter((item) => selectedKeys.includes(`${item.accountId}:${item.id}`));
|
|
2290
|
-
if (chosen.length === 0)
|
|
2367
|
+
const chosen = items.filter((item) => selectedKeys.includes(`${item.accountId}:${item.id}`)).filter((item) => item.messageId !== void 0 && item.messageId !== "");
|
|
2368
|
+
if (chosen.length === 0) {
|
|
2369
|
+
setError("\u6240\u9009\u90AE\u4EF6\u7F3A\u5C11 Message-ID\uFF0C\u65E0\u6CD5\u5173\u8054\u5230\u9879\u76EE");
|
|
2370
|
+
return;
|
|
2371
|
+
}
|
|
2291
2372
|
try {
|
|
2292
2373
|
for (const item of chosen) {
|
|
2293
2374
|
await api.addProjectMessage(targetProject, {
|
|
@@ -2906,7 +2987,7 @@ function MailPanel() {
|
|
|
2906
2987
|
}
|
|
2907
2988
|
}
|
|
2908
2989
|
}),
|
|
2909
|
-
|
|
2990
|
+
(0, import_react9.createElement)(
|
|
2910
2991
|
"button",
|
|
2911
2992
|
{
|
|
2912
2993
|
className: selectMode ? "ghost active" : "ghost",
|
|
@@ -2920,9 +3001,9 @@ function MailPanel() {
|
|
|
2920
3001
|
}
|
|
2921
3002
|
}
|
|
2922
3003
|
},
|
|
2923
|
-
Icon({ name: "
|
|
3004
|
+
Icon({ name: "list", size: 14 }),
|
|
2924
3005
|
"\u9009\u62E9"
|
|
2925
|
-
)
|
|
3006
|
+
),
|
|
2926
3007
|
query2 !== search || search !== "" ? (0, import_react9.createElement)(
|
|
2927
3008
|
"button",
|
|
2928
3009
|
{
|
|
@@ -3134,6 +3215,7 @@ function MailPanel() {
|
|
|
3134
3215
|
onReply: (mode) => startCompose(mode),
|
|
3135
3216
|
onAiAction: requestAi,
|
|
3136
3217
|
onExtractTasks: () => void extractTasks(),
|
|
3218
|
+
onAddToProject: openProjectPicker,
|
|
3137
3219
|
onClose: narrow ? () => setSelected(null) : void 0
|
|
3138
3220
|
})
|
|
3139
3221
|
),
|
|
@@ -3181,6 +3263,64 @@ function MailPanel() {
|
|
|
3181
3263
|
backup.output.length === 0 ? "\uFF08\u7B49\u5F85\u8F93\u51FA\u2026\uFF09" : backup.output.join("\n")
|
|
3182
3264
|
)
|
|
3183
3265
|
) : null,
|
|
3266
|
+
projectPicker !== null ? (0, import_react9.createElement)(
|
|
3267
|
+
Modal,
|
|
3268
|
+
{
|
|
3269
|
+
title: "\u52A0\u5165\u9879\u76EE",
|
|
3270
|
+
onClose: () => setProjectPicker(null),
|
|
3271
|
+
footer: (0, import_react9.createElement)(
|
|
3272
|
+
"div",
|
|
3273
|
+
{ style: { display: "flex", gap: "8px", width: "100%", alignItems: "center" } },
|
|
3274
|
+
(0, import_react9.createElement)("span", { className: "small muted" }, "\u628A\u8FD9\u5C01\u90AE\u4EF6\u5173\u8054\u5230\u4E00\u4E2A\u9879\u76EE"),
|
|
3275
|
+
(0, import_react9.createElement)("span", { className: "spacer" }),
|
|
3276
|
+
(0, import_react9.createElement)("button", { className: "ghost", onClick: () => setProjectPicker(null) }, "\u53D6\u6D88"),
|
|
3277
|
+
(0, import_react9.createElement)(
|
|
3278
|
+
"button",
|
|
3279
|
+
{ className: "primary", disabled: pickerBusy, onClick: () => void saveProjectPick() },
|
|
3280
|
+
pickerBusy ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58"
|
|
3281
|
+
)
|
|
3282
|
+
)
|
|
3283
|
+
},
|
|
3284
|
+
(0, import_react9.createElement)(
|
|
3285
|
+
"div",
|
|
3286
|
+
{ style: { display: "flex", flexDirection: "column", gap: "10px" } },
|
|
3287
|
+
pickerProjects.length === 0 ? (0, import_react9.createElement)("p", { className: "small muted" }, "\u8FD8\u6CA1\u6709\u9879\u76EE\uFF0C\u5728\u4E0B\u9762\u65B0\u5EFA\u4E00\u4E2A\u3002") : (0, import_react9.createElement)(
|
|
3288
|
+
"div",
|
|
3289
|
+
{ className: "mailharbor-field" },
|
|
3290
|
+
(0, import_react9.createElement)("label", null, "\u9009\u62E9\u5DF2\u6709\u9879\u76EE"),
|
|
3291
|
+
(0, import_react9.createElement)(
|
|
3292
|
+
"select",
|
|
3293
|
+
{
|
|
3294
|
+
value: pickerTarget,
|
|
3295
|
+
onChange: (event) => setPickerTarget(event.target.value)
|
|
3296
|
+
},
|
|
3297
|
+
(0, import_react9.createElement)("option", { value: "" }, "\u4E0D\u52A0\u5165\u5DF2\u6709\u9879\u76EE"),
|
|
3298
|
+
pickerProjects.map(
|
|
3299
|
+
(project) => (0, import_react9.createElement)(
|
|
3300
|
+
"option",
|
|
3301
|
+
{ key: project.id, value: project.id },
|
|
3302
|
+
`${project.name} \xB7 ${project.messages.length} \u5C01`
|
|
3303
|
+
)
|
|
3304
|
+
)
|
|
3305
|
+
)
|
|
3306
|
+
),
|
|
3307
|
+
(0, import_react9.createElement)(
|
|
3308
|
+
"div",
|
|
3309
|
+
{ className: "mailharbor-field" },
|
|
3310
|
+
(0, import_react9.createElement)("label", null, pickerProjects.length === 0 ? "\u65B0\u5EFA\u9879\u76EE" : "\u6216\u65B0\u5EFA\u9879\u76EE"),
|
|
3311
|
+
(0, import_react9.createElement)("input", {
|
|
3312
|
+
value: pickerNewName,
|
|
3313
|
+
placeholder: "\u9879\u76EE\u540D\u79F0",
|
|
3314
|
+
onChange: (event) => setPickerNewName(event.target.value)
|
|
3315
|
+
})
|
|
3316
|
+
),
|
|
3317
|
+
(0, import_react9.createElement)(
|
|
3318
|
+
"p",
|
|
3319
|
+
{ className: "small muted" },
|
|
3320
|
+
pickerTarget === "" ? "\u4FDD\u5B58\u65F6\u4F1A\u7528\u4E0A\u9762\u7684\u540D\u79F0\u521B\u5EFA\u9879\u76EE\uFF0C\u5E76\u628A\u5F53\u524D\u90AE\u4EF6\u52A0\u8FDB\u53BB\u3002" : "\u4FDD\u5B58\u540E\u8FD9\u5C01\u90AE\u4EF6\u4F1A\u51FA\u73B0\u5728\u9879\u76EE\u7684\u6765\u6E90\u90AE\u4EF6\u5217\u8868\u91CC\u3002"
|
|
3321
|
+
)
|
|
3322
|
+
)
|
|
3323
|
+
) : null,
|
|
3184
3324
|
extraction !== null ? (0, import_react9.createElement)(
|
|
3185
3325
|
Modal,
|
|
3186
3326
|
{
|
|
@@ -4504,7 +4644,7 @@ function TaskEditor({
|
|
|
4504
4644
|
}
|
|
4505
4645
|
|
|
4506
4646
|
// src/client/index.tsx
|
|
4507
|
-
var VERSION = "0.7.
|
|
4647
|
+
var VERSION = "0.7.1";
|
|
4508
4648
|
var inject = ["slots"];
|
|
4509
4649
|
var PANEL_ID = "mailharbor";
|
|
4510
4650
|
var TASKS_PANEL_ID = "mailharbor-tasks";
|