@ottttto/dsh-scheduled-send 0.3.6 → 0.3.7

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/lib/client.js CHANGED
@@ -74,12 +74,15 @@ function formatCountdown(sendAt, now) {
74
74
  const ms = sendAt - now;
75
75
  if (ms <= 0) return '即将发送';
76
76
  const totalSec = Math.floor(ms / 1000);
77
- const h = Math.floor(totalSec / 3600);
77
+ const d = Math.floor(totalSec / 86400);
78
+ const h = Math.floor((totalSec % 86400) / 3600);
78
79
  const m = Math.floor((totalSec % 3600) / 60);
79
80
  const s = totalSec % 60;
80
- if (h > 0) return `${h}小时${m}分后`;
81
- if (m > 0) return `${m}分${s}秒后`;
82
- return `${s}秒后`;
81
+ // no trailing 后 — callers append their own verb (后发送 / 后重置 …)
82
+ if (d > 0) return `${d}天${h}小时`;
83
+ if (h > 0) return `${h}小时${m}分`;
84
+ if (m > 0) return `${m}分${s}秒`;
85
+ return `${s}秒`;
83
86
  }
84
87
 
85
88
  /** Default confirmation time = now + 5 minutes. */
@@ -237,9 +240,13 @@ function createScheduledClientState({ fetchState, postSchedule, cancelSchedule,
237
240
 
238
241
  /** Cancel a pending task: DELETE on the host + drop locally. */
239
242
  async cancelTask(id) {
240
- if (cancelSchedule) await cancelSchedule(id);
243
+ // optimistic: drop locally FIRST so the row disappears instantly; the
244
+ // DELETE then persists it. onChanged lets the sibling instance (dock ↔
245
+ // sidebar panel) refresh immediately instead of waiting for its poll.
241
246
  tasks = tasks.filter((t) => t.id !== id);
242
247
  recentAdds.delete(id);
248
+ if (typeof this.onChanged === 'function') this.onChanged();
249
+ if (cancelSchedule) await cancelSchedule(id);
243
250
  },
244
251
 
245
252
  start(intervalMs = 4_000) {
@@ -487,7 +494,7 @@ function createClientPluginBody(React) {
487
494
  h("div", { key: "src", style: srcStyle }, t.content),
488
495
  h("div", { key: "meta", style: metaStyle }, [
489
496
  h("span", { key: "at" }, formatLocalTime(t.sendAt)),
490
- h("span", { key: "cd" }, formatCountdown(t.sendAt, Date.now())),
497
+ h("span", { key: "cd" }, formatCountdown(t.sendAt, Date.now()) + "后发送"),
491
498
  h("span", { key: "sp", style: { marginLeft: "auto" } }, cancelBtn(t.id)),
492
499
  ]),
493
500
  ])),
@@ -678,6 +685,10 @@ function createClientPluginBody(React) {
678
685
  const panelCore = createScheduledClientState({
679
686
  fetchState: async () => {
680
687
  const res = await doFetch(stateRoutePath, { headers: { accept: "application/json" } });
688
+ // cross-instance sync: a cancel/create in either surface refreshes the
689
+ // other immediately (no 4s poll lag)
690
+ core.onChanged = () => { void panelCore.refresh(); };
691
+ panelCore.onChanged = () => { void core.refresh(); };
681
692
  if (!res.ok) throw new Error("state HTTP " + res.status);
682
693
  return res.json();
683
694
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ottttto/dsh-scheduled-send",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "DSH plugin: scheduled sending (⏰ composer button, dock list of pending tasks, sidebar 定时任务 panel with cross-session cancel, due-time delivery as a normal user bubble)",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -65,12 +65,15 @@ export function formatCountdown(sendAt, now) {
65
65
  const ms = sendAt - now;
66
66
  if (ms <= 0) return '即将发送';
67
67
  const totalSec = Math.floor(ms / 1000);
68
- const h = Math.floor(totalSec / 3600);
68
+ const d = Math.floor(totalSec / 86400);
69
+ const h = Math.floor((totalSec % 86400) / 3600);
69
70
  const m = Math.floor((totalSec % 3600) / 60);
70
71
  const s = totalSec % 60;
71
- if (h > 0) return `${h}小时${m}分后`;
72
- if (m > 0) return `${m}分${s}秒后`;
73
- return `${s}秒后`;
72
+ // no trailing 后 — callers append their own verb (后发送 / 后重置 …)
73
+ if (d > 0) return `${d}天${h}小时`;
74
+ if (h > 0) return `${h}小时${m}分`;
75
+ if (m > 0) return `${m}分${s}秒`;
76
+ return `${s}秒`;
74
77
  }
75
78
 
76
79
  /** Default confirmation time = now + 5 minutes. */
@@ -228,9 +231,13 @@ export function createScheduledClientState({ fetchState, postSchedule, cancelSch
228
231
 
229
232
  /** Cancel a pending task: DELETE on the host + drop locally. */
230
233
  async cancelTask(id) {
231
- if (cancelSchedule) await cancelSchedule(id);
234
+ // optimistic: drop locally FIRST so the row disappears instantly; the
235
+ // DELETE then persists it. onChanged lets the sibling instance (dock ↔
236
+ // sidebar panel) refresh immediately instead of waiting for its poll.
232
237
  tasks = tasks.filter((t) => t.id !== id);
233
238
  recentAdds.delete(id);
239
+ if (typeof this.onChanged === 'function') this.onChanged();
240
+ if (cancelSchedule) await cancelSchedule(id);
234
241
  },
235
242
 
236
243
  start(intervalMs = 4_000) {
@@ -223,7 +223,7 @@ function createClientPluginBody(React) {
223
223
  h("div", { key: "src", style: srcStyle }, t.content),
224
224
  h("div", { key: "meta", style: metaStyle }, [
225
225
  h("span", { key: "at" }, formatLocalTime(t.sendAt)),
226
- h("span", { key: "cd" }, formatCountdown(t.sendAt, Date.now())),
226
+ h("span", { key: "cd" }, formatCountdown(t.sendAt, Date.now()) + "后发送"),
227
227
  h("span", { key: "sp", style: { marginLeft: "auto" } }, cancelBtn(t.id)),
228
228
  ]),
229
229
  ])),
@@ -414,6 +414,10 @@ function createClientPluginBody(React) {
414
414
  const panelCore = createScheduledClientState({
415
415
  fetchState: async () => {
416
416
  const res = await doFetch(stateRoutePath, { headers: { accept: "application/json" } });
417
+ // cross-instance sync: a cancel/create in either surface refreshes the
418
+ // other immediately (no 4s poll lag)
419
+ core.onChanged = () => { void panelCore.refresh(); };
420
+ panelCore.onChanged = () => { void core.refresh(); };
417
421
  if (!res.ok) throw new Error("state HTTP " + res.status);
418
422
  return res.json();
419
423
  },