@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 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) return;
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
- source === "local" ? (0, import_react9.createElement)(
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: "checklist", size: 14 }),
3004
+ Icon({ name: "list", size: 14 }),
2924
3005
  "\u9009\u62E9"
2925
- ) : null,
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.0";
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";