Compare commits

..
2 changed files with 4 additions and 34 deletions

View file

@ -245,13 +245,6 @@ checked-not-originally-active = `targets_add`; submit PATCHes
`/api/schedules/{id}`), and a `✕` button cancels the whole
schedule (`POST /api/schedules/{id}/cancel`).
The `next` column cell (`.sched-due`) carries a `data-due-at`
Unix timestamp attribute; a shared 1s ticker rewrites it
in-place showing `fmtDuration` while in the future and
`overdue X ago` once the fire time has passed — same
zero-re-render pattern as the reminder due-at labels and the
question TTL chip.
The table's last row is a permanent inline creation row:
inputs live directly in table cells (targets as checkboxes,
body textarea that expands on focus, datetime-local pre-filled
@ -272,12 +265,7 @@ button hard-deletes (`POST /cancel-reminder/{id}`) and a
`R3TRY` button re-arms one whose delivery failed
(`POST /retry-reminder/{id}`). Backed by `GET /api/reminders`.
Lives in the SCH3DUL3S tab alongside operator schedules so the
operator has one place for everything time-fired. The due-time
label (`.reminder-due`) carries a `data-due-at` Unix timestamp
attribute; a shared 1s ticker rewrites it in-place — showing
`in Xm Ys` while the reminder is in the future and
`overdue X ago` once the deadline passes — without triggering a
full re-render of the list.
operator has one place for everything time-fired.
## P33RS tab

View file

@ -455,7 +455,8 @@ window.marked = marked;
menuItem('↻ R3BU1LD', { action: '/rebuild/', confirm: `rebuild ${c.name}? hot-reloads the container.` }),
menuSep(),
// Deep-link to the AGENT log tab pre-filtered to this container.
// The ?agent= param is read by logs.js on load and pre-selects this
// The ?agent= param is read by logs.js on load; the stored localStorage
// selection is overridden so the operator lands directly in this
// agent's journal without extra clicks.
menuLink('journal logs →',
`/logs.html?agent=${encodeURIComponent(c.name)}#agent`,
@ -1998,11 +1999,6 @@ window.marked = marked;
// a request pending for an hour could still show "0s ago" without
// this ticker. Also flips `.stale` (amber highlight) at exactly 1h
// rather than only at the next re-render.
// Live countdown for reminder due-at labels and schedule next-fire
// cells. Both renderers stamp `data-due-at` on the element so this
// single ticker keeps them fresh without triggering a full re-render.
// `.reminder-due` → "overdue X ago" / "in Y"
// `.sched-due` → same pattern
setInterval(() => {
const now = Math.floor(Date.now() / 1000);
document.querySelectorAll('.approval-ts[data-requested-at]').forEach((node) => {
@ -2012,14 +2008,6 @@ window.marked = marked;
node.textContent = 'requested ' + fmtAgo(requestedAt);
node.classList.toggle('stale', ageSec >= 3600);
});
document.querySelectorAll('.reminder-due[data-due-at], .sched-due[data-due-at]').forEach((node) => {
const dueAt = Number(node.getAttribute('data-due-at'));
if (!Number.isFinite(dueAt)) return;
const dueIn = dueAt - now;
node.textContent = dueIn <= 0
? 'overdue ' + fmtAgo(dueAt)
: (node.classList.contains('reminder-due') ? 'in ' : '') + fmtDuration(dueIn);
});
}, 1000);
const APPROVAL_TAB_KEY = 'hyperhive:approvals:tab';
@ -2802,11 +2790,7 @@ window.marked = marked;
: `in ${fmtDuration(dueIn)}`;
const head = el('div', { class: 'reminder-head' },
el('span', { class: 'agent' }, r.agent), ' ',
el('span', {
class: 'meta reminder-due',
title: new Date(r.due_at * 1000).toISOString(),
'data-due-at': String(r.due_at),
}, dueLabel),
el('span', { class: 'meta', title: new Date(r.due_at * 1000).toISOString() }, dueLabel),
' ',
el('span', { class: 'meta' }, `· id ${r.id}`),
);
@ -3409,8 +3393,6 @@ window.marked = marked;
nextCell.textContent = dueIn <= 0
? 'overdue ' + fmtAgo(s.next_fire_at_unix)
: fmtDuration(dueIn);
nextCell.classList.add('sched-due');
nextCell.dataset.dueAt = String(s.next_fire_at_unix);
}
tr.append(nextCell);