agent-office 0.0.11 → 0.0.12
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.
|
@@ -429,15 +429,22 @@ function renderPage(coworker, msgs, humanName) {
|
|
|
429
429
|
const input = document.getElementById('msg-input')
|
|
430
430
|
|
|
431
431
|
let lastSeenId = parseInt(document.querySelector('#messages-inner')?.dataset?.lastId ?? '0', 10)
|
|
432
|
-
let
|
|
432
|
+
let userScrolledUp = false
|
|
433
433
|
|
|
434
434
|
function scrollToBottom() {
|
|
435
|
-
if (outer)
|
|
435
|
+
if (!outer) return
|
|
436
|
+
requestAnimationFrame(() => {
|
|
437
|
+
outer.scrollTop = outer.scrollHeight
|
|
438
|
+
// After snapping, clear the flag so future messages auto-scroll again
|
|
439
|
+
userScrolledUp = false
|
|
440
|
+
})
|
|
436
441
|
}
|
|
437
442
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
443
|
+
// Detect when the user manually scrolls up
|
|
444
|
+
outer.addEventListener('scroll', () => {
|
|
445
|
+
const distFromBottom = outer.scrollHeight - outer.scrollTop - outer.clientHeight
|
|
446
|
+
userScrolledUp = distFromBottom > 80
|
|
447
|
+
})
|
|
441
448
|
|
|
442
449
|
// Auto-grow textarea
|
|
443
450
|
input.addEventListener('input', function() {
|
|
@@ -454,7 +461,7 @@ function renderPage(coworker, msgs, humanName) {
|
|
|
454
461
|
}
|
|
455
462
|
}
|
|
456
463
|
|
|
457
|
-
// After send: clear input, re-enable button,
|
|
464
|
+
// After send: clear input, re-enable button, force scroll and refresh
|
|
458
465
|
function handleSent(event) {
|
|
459
466
|
const form = event.target
|
|
460
467
|
const btn = form.querySelector('.send-btn')
|
|
@@ -463,22 +470,20 @@ function renderPage(coworker, msgs, humanName) {
|
|
|
463
470
|
input.value = ''
|
|
464
471
|
input.style.height = 'auto'
|
|
465
472
|
input.focus()
|
|
466
|
-
|
|
473
|
+
userScrolledUp = false
|
|
467
474
|
lastSeenId = -1
|
|
468
|
-
forceNextScroll = true
|
|
469
475
|
htmx.trigger(document.getElementById('messages'), 'load')
|
|
470
476
|
}
|
|
471
477
|
}
|
|
472
478
|
|
|
473
|
-
//
|
|
479
|
+
// Scroll to bottom whenever new messages arrive, unless user has scrolled up
|
|
474
480
|
document.addEventListener('htmx:afterSwap', (e) => {
|
|
475
481
|
if (e.detail.target.id !== 'messages') return
|
|
476
482
|
const inner = document.getElementById('messages-inner')
|
|
477
483
|
const newLastId = parseInt(inner?.dataset?.lastId ?? '0', 10)
|
|
478
484
|
if (newLastId > lastSeenId) {
|
|
479
485
|
lastSeenId = newLastId
|
|
480
|
-
if (
|
|
481
|
-
forceNextScroll = false
|
|
486
|
+
if (!userScrolledUp) scrollToBottom()
|
|
482
487
|
}
|
|
483
488
|
})
|
|
484
489
|
|
|
@@ -39,7 +39,7 @@ export function CronList({ serverUrl, password, onBack, contentHeight, sessionNa
|
|
|
39
39
|
onBack();
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
|
-
if (key.escape && (mode === "confirm-delete" || mode === "confirm-enable" || mode === "confirm-disable" || mode === "history")) {
|
|
42
|
+
if (key.escape && (mode === "confirm-delete" || mode === "confirm-enable" || mode === "confirm-disable" || mode === "history" || mode === "view-message")) {
|
|
43
43
|
setMode("list");
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
@@ -81,6 +81,9 @@ export function CronList({ serverUrl, password, onBack, contentHeight, sessionNa
|
|
|
81
81
|
setActionError(null);
|
|
82
82
|
loadHistory(selected.id);
|
|
83
83
|
}
|
|
84
|
+
if (input === "v") {
|
|
85
|
+
setMode("view-message");
|
|
86
|
+
}
|
|
84
87
|
}
|
|
85
88
|
}
|
|
86
89
|
if (mode === "confirm-delete" || mode === "confirm-enable" || mode === "confirm-disable") {
|
|
@@ -290,6 +293,14 @@ export function CronList({ serverUrl, password, onBack, contentHeight, sessionNa
|
|
|
290
293
|
}
|
|
291
294
|
return null;
|
|
292
295
|
};
|
|
296
|
+
const renderViewMessage = () => {
|
|
297
|
+
if (mode !== "view-message")
|
|
298
|
+
return null;
|
|
299
|
+
const selected = filteredCrons[cursor];
|
|
300
|
+
if (!selected)
|
|
301
|
+
return null;
|
|
302
|
+
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Message Preview" }), _jsx(Text, { dimColor: true, children: selected.name })] }), _jsx(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1, paddingY: 0, flexDirection: "column", children: _jsx(Text, { wrap: "wrap", children: selected.message }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Esc back" }) })] }));
|
|
303
|
+
};
|
|
293
304
|
const renderHistory = () => {
|
|
294
305
|
if (mode !== "history")
|
|
295
306
|
return null;
|
|
@@ -301,10 +312,10 @@ export function CronList({ serverUrl, password, onBack, contentHeight, sessionNa
|
|
|
301
312
|
const actionPanel = renderActionPanel();
|
|
302
313
|
const panelHeight = actionPanel ? 5 : 0;
|
|
303
314
|
const tableHeight = contentHeight - panelHeight - 5;
|
|
304
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 0, children: [renderCreateSelectSession(), renderCreateFields(), renderHistory(), (mode === "list" || mode === "confirm-delete" || mode === "confirm-enable" || mode === "confirm-disable" || mode === "deleting" || mode === "toggling") && (_jsxs(_Fragment, { children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Cron Jobs" }), selectedSession ? (_jsxs(Text, { color: "cyan", dimColor: true, children: ["[", filteredCrons.length, " jobs for ", selectedSession, "]"] })) : (_jsxs(Text, { dimColor: true, children: ["[", filteredCrons.length, " total]"] })), loading && _jsx(Spinner, {})] }), actionPanel, filteredCrons.length === 0 ? (_jsx(Box, { height: tableHeight, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: selectedSession
|
|
315
|
+
return (_jsxs(Box, { flexDirection: "column", gap: 0, children: [renderCreateSelectSession(), renderCreateFields(), renderViewMessage(), renderHistory(), (mode === "list" || mode === "confirm-delete" || mode === "confirm-enable" || mode === "confirm-disable" || mode === "deleting" || mode === "toggling" || mode === "view-message") && (_jsxs(_Fragment, { children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Cron Jobs" }), selectedSession ? (_jsxs(Text, { color: "cyan", dimColor: true, children: ["[", filteredCrons.length, " jobs for ", selectedSession, "]"] })) : (_jsxs(Text, { dimColor: true, children: ["[", filteredCrons.length, " total]"] })), loading && _jsx(Spinner, {})] }), actionPanel, filteredCrons.length === 0 ? (_jsx(Box, { height: tableHeight, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: selectedSession
|
|
305
316
|
? `No cron jobs for ${selectedSession}. Press c to create one.`
|
|
306
317
|
: "No cron jobs yet. Press c to create one." }) })) : (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: " NAME".padEnd(20) }), _jsx(Text, { bold: true, color: "cyan", children: "COWORKER".padEnd(15) }), _jsx(Text, { bold: true, color: "cyan", children: "SCHEDULE".padEnd(20) }), _jsx(Text, { bold: true, color: "cyan", children: "NEXT RUN".padEnd(NEXT_RUN_PADDING) }), _jsx(Text, { bold: true, color: "cyan", children: "STATUS" })] }), filteredCrons.map((job, idx) => {
|
|
307
318
|
const selected = idx === cursor;
|
|
308
319
|
return (_jsxs(Box, { gap: 2, children: [_jsxs(Box, { width: 20, children: [_jsx(Text, { color: selected ? "cyan" : undefined, children: selected ? "▶ " : " " }), _jsx(Text, { color: selected ? "cyan" : "green", bold: selected, children: job.name })] }), _jsx(Box, { width: 15, children: _jsx(Text, { color: selected ? "magenta" : undefined, dimColor: !selected, children: job.session_name.padEnd(15) }) }), _jsx(Box, { width: 20, children: _jsx(Text, { dimColor: !selected, children: job.schedule.padEnd(20) }) }), _jsx(Box, { width: NEXT_RUN_PADDING, children: _jsx(Text, { color: job.enabled ? (selected ? "cyan" : "green") : "gray", dimColor: !selected, children: job.enabled ? formatNextRun(job.next_run).padEnd(NEXT_RUN_PADDING) : "DISABLED".padEnd(NEXT_RUN_PADDING) }) }), _jsx(Text, { color: job.enabled ? "green" : "gray", dimColor: !selected, children: job.enabled ? "enabled" : "disabled" })] }, job.id));
|
|
309
|
-
})] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["c create \u00B7 d delete \u00B7 e enable/disable \u00B7 h history \u00B7 f", " ", selectedSession ? "show all" : "filter by coworker", " \u00B7 Esc back"] }) })] }))] }));
|
|
320
|
+
})] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["c create \u00B7 d delete \u00B7 e enable/disable \u00B7 h history \u00B7 v view message \u00B7 f", " ", selectedSession ? "show all" : "filter by coworker", " \u00B7 Esc back"] }) })] }))] }));
|
|
310
321
|
}
|