Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 3 additions & 15 deletions relay/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,9 +463,6 @@ function buildBoardHtml(rows: ProjectRow[], updatedAt: string, todos: TodoRow[]
.patina { color: #2E9E6E; }
.working { color: #20A890; }
.idle { color: rgba(168,168,168,0.65); }
/* Countdown */
.countdown { color: rgba(168,168,168,0.8); }
.countdown.warn { color: #E8553D; }
/* TODO CRUD */
.todo-actions { display: inline-flex; gap: 4px; margin-left: 8px; opacity: 0; transition: opacity 0.15s; }
.row:hover .todo-actions, .row:focus-within .todo-actions { opacity: 1; }
Expand Down Expand Up @@ -516,7 +513,7 @@ function buildBoardHtml(rows: ProjectRow[], updatedAt: string, todos: TodoRow[]
<span class="titlebar-label">$ tend</span>
</div>
<nav class="statusbar" aria-label="Board status">
<span>tend board &nbsp;·&nbsp; updated <time id="updated-at"></time> &nbsp;·&nbsp; next refresh in <span id="countdown" class="countdown">60s</span></span>
<span>tend board &nbsp;·&nbsp; updated <time id="updated-at"></time></span>
<span>tend.cx</span>
</nav>
<main class="board" role="main">
Expand Down Expand Up @@ -599,17 +596,8 @@ function buildBoardHtml(rows: ProjectRow[], updatedAt: string, todos: TodoRow[]
el.textContent = ts ? '(' + timeAgo(ts) + ')' : '';
});

// Countdown + auto-refresh
var secs = 60;
var cdEl = document.getElementById('countdown');
setInterval(function() {
secs--;
if (secs <= 0) { location.reload(); return; }
if (cdEl) {
cdEl.textContent = secs + 's';
cdEl.className = 'countdown' + (secs <= 10 ? ' warn' : '');
}
}, 1000);
// Auto-refresh
setInterval(function() { location.reload(); }, 60000);

// TODO CRUD (only active when token is writable)
var TOKEN = '${rawToken}';
Expand Down
3 changes: 1 addition & 2 deletions relay/test/relay.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,15 +462,14 @@ describe('Tend Relay', () => {
expect(html).not.toContain(`data-ts="${oldTs}"`);
});

it('auto-refresh countdown script is present', async () => {
it('auto-refresh script is present', async () => {
const token = await registerToken();
const request = new Request(`http://localhost/${token}`, { method: 'GET' });
const ctx = createExecutionContext();
const response = await worker.fetch(request, env, ctx);
await waitOnExecutionContext(ctx);
const html = await response.text();
expect(html).toContain('location.reload');
expect(html).toContain('countdown');
});

it('isolates boards between tokens', async () => {
Expand Down
14 changes: 4 additions & 10 deletions src/commands/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,14 @@ function formatTime(d: Date): string {
return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
}

function countdown(secs: number): string {
if (secs <= 0) return 'refreshing…';
if (secs < 60) return `${secs}s`;
return `${Math.floor(secs / 60)}m ${secs % 60}s`;
}

/** Strip ANSI escape codes to measure visible width. */
function visibleLen(s: string): number {
return s.replace(/\x1b\[[^m]*m/g, '').length;
}

function renderHeaderLines(lastUpdated: string, secsLeft: number): string {
function renderHeaderLines(lastUpdated: string): string {
const w = process.stdout.columns || 80;
const left = ` ${C.bold}tend${C.reset} dashboard · updated ${lastUpdated} · next refresh in ${countdown(secsLeft)}`;
const left = ` ${C.bold}tend${C.reset} dashboard · updated ${lastUpdated}`;
const right = ` q to quit `;
const pad = Math.max(0, w - visibleLen(left) - right.length);
const line1 = left + ' '.repeat(pad) + right;
Expand Down Expand Up @@ -70,7 +64,7 @@ export async function cmdDashboard(): Promise<void> {
/** Overwrite just the top two header lines without touching the board body. */
function updateHeader(): void {
const w = process.stdout.columns || 80;
const statusLine = renderHeaderLines(lastUpdated, secsLeft).split('\n')[0];
const statusLine = renderHeaderLines(lastUpdated).split('\n')[0];
const divider = '─'.repeat(w);
// Move to row 1, clear it, write status; move to row 2, clear it, write divider
process.stdout.write(`${ESC}[1;1H${ESC}[2K${statusLine}\n${ESC}[2K${divider}`);
Expand All @@ -79,7 +73,7 @@ export async function cmdDashboard(): Promise<void> {
/** Full screen redraw: clear, write header, then board content. */
function fullDraw(): void {
process.stdout.write(`${ESC}[2J${ESC}[H`);
process.stdout.write(renderHeaderLines(lastUpdated, secsLeft) + '\n');
process.stdout.write(renderHeaderLines(lastUpdated) + '\n');
process.stdout.write(boardContent);
}

Expand Down
15 changes: 1 addition & 14 deletions www/app/components.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,6 @@ export function ArrowRightIconExport() {
}

export function DashboardLive() {
const [tick, setTick] = useState(0)
const REFRESH_SECS = 60
const REFRESH_WARNING_THRESHOLD = 10

useEffect(() => {
const interval = setInterval(() => setTick(t => t + 1), 1000)
return () => clearInterval(interval)
}, [])

const secsLeft = Math.max(0, REFRESH_SECS - (tick % REFRESH_SECS))
const countdown = secsLeft < REFRESH_SECS ? `${secsLeft}s` : '1m 0s'

const rows = [
{ icon: '?', name: 'atlas-api', state: 'stuck', msg: 'needs database credentials for staging', right: '', stateColor: 'text-ember' },
{ icon: '\u25d0', name: 'northstar', state: 'working', msg: 'refactoring auth middleware', right: '(8m)', stateColor: 'text-patina' },
Expand All @@ -181,8 +169,7 @@ export function DashboardLive() {
<div className="px-4 py-2 border-b border-white/5 font-mono text-[11px] flex justify-between text-smoke/40">
<span>
<span className="text-parchment/60 font-medium">tend</span>
{' '}dashboard \u00b7 updated {timeStr} \u00b7 next refresh in{' '}
<span className={secsLeft <= REFRESH_WARNING_THRESHOLD ? 'text-ember' : 'text-smoke/40'}>{countdown}</span>
{' '}dashboard \u00b7 updated {timeStr}
</span>
<span>q to quit</span>
</div>
Expand Down
Loading