@ottttto/dsh-scheduled-send 0.3.0 → 0.3.2
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 +21 -8
- package/package.json +2 -2
- package/src/client-view.js +21 -8
package/lib/client.js
CHANGED
|
@@ -315,6 +315,9 @@ function createClientPluginBody(React) {
|
|
|
315
315
|
try {
|
|
316
316
|
const payload = { content, sendAt: at, conversationId: props.sessionId };
|
|
317
317
|
await core.scheduleMessage(payload);
|
|
318
|
+
// sidebar panel has its own state: refresh it NOW (its 8s poll would
|
|
319
|
+
// otherwise lag ~10s behind a fresh task)
|
|
320
|
+
if (props.onTaskCreated) void props.onTaskCreated();
|
|
318
321
|
// spec: 内容转为定时任务并清空输入框 — 绝不立即发送(不调 submit)
|
|
319
322
|
if (props.inputActions && typeof props.inputActions.setDraft === "function") props.inputActions.setDraft("");
|
|
320
323
|
setOpen(false);
|
|
@@ -496,6 +499,7 @@ function createClientPluginBody(React) {
|
|
|
496
499
|
const core = props.panelCore;
|
|
497
500
|
const [open, setOpen] = React.useState(false);
|
|
498
501
|
const [tick, setTick] = React.useState(0);
|
|
502
|
+
const [hover, setHover] = React.useState(false);
|
|
499
503
|
const mobile = isMobile();
|
|
500
504
|
|
|
501
505
|
// keep the badge alive even while the panel is closed: poll the FULL
|
|
@@ -521,11 +525,13 @@ function createClientPluginBody(React) {
|
|
|
521
525
|
|
|
522
526
|
const isDark = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
523
527
|
const entryBtn = {
|
|
524
|
-
cursor: "pointer", display: "
|
|
525
|
-
|
|
526
|
-
|
|
528
|
+
cursor: "pointer", display: "flex", alignItems: "center", gap: 8,
|
|
529
|
+
width: "100%", boxSizing: "border-box", textAlign: "left",
|
|
530
|
+
border: "none", background: hover ? "rgba(128,128,128,.16)" : "transparent", color: "inherit",
|
|
531
|
+
fontSize: 12, fontWeight: 600, padding: "6px 10px", borderRadius: 8, whiteSpace: "nowrap",
|
|
527
532
|
...(mobile ? { minHeight: TOUCH_MIN } : {}),
|
|
528
533
|
};
|
|
534
|
+
const iconBox = { display: "inline-flex", width: 16, justifyContent: "center", flexShrink: 0 };
|
|
529
535
|
const badge = (n) => h("span", {
|
|
530
536
|
key: "b", "data-badge": n,
|
|
531
537
|
style: {
|
|
@@ -620,14 +626,18 @@ function createClientPluginBody(React) {
|
|
|
620
626
|
])
|
|
621
627
|
: null;
|
|
622
628
|
|
|
623
|
-
return h("div", { "data-plugin": "dsh-scheduled-send-sidebar", style: {
|
|
629
|
+
return h("div", { "data-plugin": "dsh-scheduled-send-sidebar", style: { width: "100%" } }, [
|
|
630
|
+
null,
|
|
624
631
|
h("button", {
|
|
625
632
|
key: "btn", type: "button",
|
|
633
|
+
onMouseEnter: () => setHover(true),
|
|
634
|
+
onMouseLeave: () => setHover(false),
|
|
626
635
|
onClick: () => { setOpen(!open); setTick((n) => n + 1); },
|
|
627
636
|
title: "定时任务", "aria-label": "定时任务", style: entryBtn,
|
|
628
637
|
}, [
|
|
629
|
-
h("span", { key: "
|
|
630
|
-
|
|
638
|
+
h("span", { key: "i", style: iconBox }, "⏰"),
|
|
639
|
+
h("span", { key: "l" }, "定时任务"),
|
|
640
|
+
all.length ? h("span", { key: "bs", style: { marginLeft: "auto", display: "inline-flex" } }, badge(all.length)) : null,
|
|
631
641
|
]),
|
|
632
642
|
footer,
|
|
633
643
|
]);
|
|
@@ -687,6 +697,9 @@ function createClientPluginBody(React) {
|
|
|
687
697
|
|
|
688
698
|
const inject = ["slots", "sessions"]; // sessions: sidebar panel jump (0.3.0)
|
|
689
699
|
function apply(ctx) {
|
|
700
|
+
// due-time delivery: refresh the sidebar panel the moment a task fires
|
|
701
|
+
ctx.on?.('guard/scheduled-due', () => { void panelCore.refresh(); });
|
|
702
|
+
ctx.on?.('guard/scheduled-dropped', () => { void panelCore.refresh(); });
|
|
690
703
|
ctx.inject(inject, (scope) => {
|
|
691
704
|
// 0.3.0 session navigation, sourced from the sessions service:
|
|
692
705
|
// - open(id) selects a session as current (unknown ids throw → false)
|
|
@@ -714,7 +727,7 @@ function createClientPluginBody(React) {
|
|
|
714
727
|
inject: (sessionId) => {
|
|
715
728
|
currentSessionId = sessionId;
|
|
716
729
|
core.setSession(sessionId); // dock/button are conversation-scoped
|
|
717
|
-
return { sessionId, core };
|
|
730
|
+
return { sessionId, core, onTaskCreated: () => panelCore.refresh() };
|
|
718
731
|
},
|
|
719
732
|
}, ScheduleButton));
|
|
720
733
|
scope.slots.inject("conversation.input.dock", () => scope.slots.register({
|
|
@@ -724,7 +737,7 @@ function createClientPluginBody(React) {
|
|
|
724
737
|
inject: (sessionId) => {
|
|
725
738
|
currentSessionId = sessionId;
|
|
726
739
|
core.setSession(sessionId);
|
|
727
|
-
return { sessionId, core };
|
|
740
|
+
return { sessionId, core, onTaskCreated: () => panelCore.refresh() };
|
|
728
741
|
},
|
|
729
742
|
}, ScheduledDock));
|
|
730
743
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ottttto/dsh-scheduled-send",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
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",
|
|
@@ -52,4 +52,4 @@
|
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": ">=18"
|
|
54
54
|
}
|
|
55
|
-
}
|
|
55
|
+
}
|
package/src/client-view.js
CHANGED
|
@@ -51,6 +51,9 @@ function createClientPluginBody(React) {
|
|
|
51
51
|
try {
|
|
52
52
|
const payload = { content, sendAt: at, conversationId: props.sessionId };
|
|
53
53
|
await core.scheduleMessage(payload);
|
|
54
|
+
// sidebar panel has its own state: refresh it NOW (its 8s poll would
|
|
55
|
+
// otherwise lag ~10s behind a fresh task)
|
|
56
|
+
if (props.onTaskCreated) void props.onTaskCreated();
|
|
54
57
|
// spec: 内容转为定时任务并清空输入框 — 绝不立即发送(不调 submit)
|
|
55
58
|
if (props.inputActions && typeof props.inputActions.setDraft === "function") props.inputActions.setDraft("");
|
|
56
59
|
setOpen(false);
|
|
@@ -232,6 +235,7 @@ function createClientPluginBody(React) {
|
|
|
232
235
|
const core = props.panelCore;
|
|
233
236
|
const [open, setOpen] = React.useState(false);
|
|
234
237
|
const [tick, setTick] = React.useState(0);
|
|
238
|
+
const [hover, setHover] = React.useState(false);
|
|
235
239
|
const mobile = isMobile();
|
|
236
240
|
|
|
237
241
|
// keep the badge alive even while the panel is closed: poll the FULL
|
|
@@ -257,11 +261,13 @@ function createClientPluginBody(React) {
|
|
|
257
261
|
|
|
258
262
|
const isDark = typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
259
263
|
const entryBtn = {
|
|
260
|
-
cursor: "pointer", display: "
|
|
261
|
-
|
|
262
|
-
|
|
264
|
+
cursor: "pointer", display: "flex", alignItems: "center", gap: 8,
|
|
265
|
+
width: "100%", boxSizing: "border-box", textAlign: "left",
|
|
266
|
+
border: "none", background: hover ? "rgba(128,128,128,.16)" : "transparent", color: "inherit",
|
|
267
|
+
fontSize: 12, fontWeight: 600, padding: "6px 10px", borderRadius: 8, whiteSpace: "nowrap",
|
|
263
268
|
...(mobile ? { minHeight: TOUCH_MIN } : {}),
|
|
264
269
|
};
|
|
270
|
+
const iconBox = { display: "inline-flex", width: 16, justifyContent: "center", flexShrink: 0 };
|
|
265
271
|
const badge = (n) => h("span", {
|
|
266
272
|
key: "b", "data-badge": n,
|
|
267
273
|
style: {
|
|
@@ -356,14 +362,18 @@ function createClientPluginBody(React) {
|
|
|
356
362
|
])
|
|
357
363
|
: null;
|
|
358
364
|
|
|
359
|
-
return h("div", { "data-plugin": "dsh-scheduled-send-sidebar", style: {
|
|
365
|
+
return h("div", { "data-plugin": "dsh-scheduled-send-sidebar", style: { width: "100%" } }, [
|
|
366
|
+
null,
|
|
360
367
|
h("button", {
|
|
361
368
|
key: "btn", type: "button",
|
|
369
|
+
onMouseEnter: () => setHover(true),
|
|
370
|
+
onMouseLeave: () => setHover(false),
|
|
362
371
|
onClick: () => { setOpen(!open); setTick((n) => n + 1); },
|
|
363
372
|
title: "定时任务", "aria-label": "定时任务", style: entryBtn,
|
|
364
373
|
}, [
|
|
365
|
-
h("span", { key: "
|
|
366
|
-
|
|
374
|
+
h("span", { key: "i", style: iconBox }, "⏰"),
|
|
375
|
+
h("span", { key: "l" }, "定时任务"),
|
|
376
|
+
all.length ? h("span", { key: "bs", style: { marginLeft: "auto", display: "inline-flex" } }, badge(all.length)) : null,
|
|
367
377
|
]),
|
|
368
378
|
footer,
|
|
369
379
|
]);
|
|
@@ -423,6 +433,9 @@ function createClientPluginBody(React) {
|
|
|
423
433
|
|
|
424
434
|
const inject = ["slots", "sessions"]; // sessions: sidebar panel jump (0.3.0)
|
|
425
435
|
function apply(ctx) {
|
|
436
|
+
// due-time delivery: refresh the sidebar panel the moment a task fires
|
|
437
|
+
ctx.on?.('guard/scheduled-due', () => { void panelCore.refresh(); });
|
|
438
|
+
ctx.on?.('guard/scheduled-dropped', () => { void panelCore.refresh(); });
|
|
426
439
|
ctx.inject(inject, (scope) => {
|
|
427
440
|
// 0.3.0 session navigation, sourced from the sessions service:
|
|
428
441
|
// - open(id) selects a session as current (unknown ids throw → false)
|
|
@@ -450,7 +463,7 @@ function createClientPluginBody(React) {
|
|
|
450
463
|
inject: (sessionId) => {
|
|
451
464
|
currentSessionId = sessionId;
|
|
452
465
|
core.setSession(sessionId); // dock/button are conversation-scoped
|
|
453
|
-
return { sessionId, core };
|
|
466
|
+
return { sessionId, core, onTaskCreated: () => panelCore.refresh() };
|
|
454
467
|
},
|
|
455
468
|
}, ScheduleButton));
|
|
456
469
|
scope.slots.inject("conversation.input.dock", () => scope.slots.register({
|
|
@@ -460,7 +473,7 @@ function createClientPluginBody(React) {
|
|
|
460
473
|
inject: (sessionId) => {
|
|
461
474
|
currentSessionId = sessionId;
|
|
462
475
|
core.setSession(sessionId);
|
|
463
|
-
return { sessionId, core };
|
|
476
|
+
return { sessionId, core, onTaskCreated: () => panelCore.refresh() };
|
|
464
477
|
},
|
|
465
478
|
}, ScheduledDock));
|
|
466
479
|
});
|