Show relative time in resume picker

This commit is contained in:
weishu
2026-05-20 20:24:46 +08:00
parent 1bd0bb2cf7
commit 62ac4e7b0a
3 changed files with 34 additions and 1 deletions
+3 -1
View File
@@ -3,6 +3,7 @@ import { Box, Text, useInput, useStdout } from 'ink'
import type { ResumableSession } from '@hapi/protocol'
import {
filterResumeSessions,
formatResumeSessionRelativeTime,
getResumeSessionName,
getResumeSessionState,
normalizeScrollOffset,
@@ -41,7 +42,8 @@ function truncateText(value: string, maxLength: number): string {
function formatSessionLine(session: ResumableSession, width: number): string {
const state = getResumeSessionState(session)
const prefix = `${session.flavor.padEnd(8)} ${state.padEnd(8)} `
const time = formatResumeSessionRelativeTime(session.updatedAt).padStart(10)
const prefix = `${time} ${session.flavor.padEnd(8)} ${state.padEnd(8)} `
const directoryBudget = Math.max(16, Math.floor(width * 0.35))
const nameBudget = Math.max(12, width - prefix.length - directoryBudget - 2)
const name = truncateText(getResumeSessionName(session), nameBudget)
@@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest'
import type { ResumableSession } from '@hapi/protocol'
import {
filterResumeSessions,
formatResumeSessionRelativeTime,
reducePickerState,
type PickerState
} from './resumeSessionPickerState'
@@ -22,6 +23,17 @@ function session(overrides: Partial<ResumableSession>): ResumableSession {
}
describe('resumeSessionPickerState', () => {
it('formats updatedAt as relative time', () => {
const now = 1_700_000_000_000
expect(formatResumeSessionRelativeTime(now - 10_000, now)).toBe('now')
expect(formatResumeSessionRelativeTime(now - 5 * 60_000, now)).toBe('5m ago')
expect(formatResumeSessionRelativeTime(now - 3 * 60 * 60_000, now)).toBe('3h ago')
expect(formatResumeSessionRelativeTime(now - 2 * 24 * 60 * 60_000, now)).toBe('2d ago')
expect(formatResumeSessionRelativeTime(Math.floor((now - 5 * 60_000) / 1000), now)).toBe('5m ago')
expect(formatResumeSessionRelativeTime(NaN, now)).toBe('unknown')
})
it('filters sessions by searchable fields case-insensitively', () => {
const sessions = [
session({
@@ -25,6 +25,25 @@ export function getResumeSessionState(session: ResumableSession): string {
return session.controlledByUser ? 'local' : 'remote'
}
export function formatResumeSessionRelativeTime(value: number, now: number = Date.now()): string {
const ms = value < 1_000_000_000_000 ? value * 1000 : value
if (!Number.isFinite(ms)) return 'unknown'
const delta = Math.max(0, now - ms)
if (delta < 60_000) return 'now'
const minutes = Math.floor(delta / 60_000)
if (minutes < 60) return `${minutes}m ago`
const hours = Math.floor(minutes / 60)
if (hours < 24) return `${hours}h ago`
const days = Math.floor(hours / 24)
if (days < 7) return `${days}d ago`
return new Date(ms).toLocaleDateString()
}
export function filterResumeSessions(
sessions: ResumableSession[],
query: string