mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
fix(mobile): stop double-scaling commit timestamps in history rows (#17731)
Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
This commit is contained in:
co-authored by
Claude
Jinwoo-H
parent
1ae7aa8bb4
commit
c300913f90
@@ -27,11 +27,24 @@ vi.mock('react-native', () => ({
|
||||
vi.mock('lucide-react-native', () => ({ ChevronDown: 'ChevronDown', ChevronRight: 'ChevronRight' }))
|
||||
vi.mock('../transport/client-context', () => ({ useForceReconnect: () => vi.fn() }))
|
||||
|
||||
// Captured at module scope: the list renders rows against Date.now() a few ms later,
|
||||
// so a 3h offset stays inside the '3h' relative-time bucket.
|
||||
const RENDER_NOW = Date.now()
|
||||
|
||||
function historyResponse(subject: string) {
|
||||
return {
|
||||
ok: true,
|
||||
result: {
|
||||
items: [{ id: 'commit-1', displayId: 'c0mm1t1', subject, author: 'Ada', parentIds: [] }]
|
||||
items: [
|
||||
{
|
||||
id: 'commit-1',
|
||||
displayId: 'c0mm1t1',
|
||||
subject,
|
||||
author: 'Ada',
|
||||
parentIds: [],
|
||||
timestamp: RENDER_NOW - 3 * 3_600_000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,6 +105,9 @@ describe('MobileGitHistoryList', () => {
|
||||
|
||||
await render(client, 'connected')
|
||||
expect(tree()).toContain('first load')
|
||||
// Rows format the RPC timestamp (epoch ms); a regression to seconds-scaling
|
||||
// renders every commit as 'just now' instead.
|
||||
expect(tree()).toContain('3h')
|
||||
|
||||
await update(client, 'reconnecting')
|
||||
expect(tree()).toContain('first load')
|
||||
|
||||
@@ -11,20 +11,21 @@ function item(overrides: Partial<GitHistoryItem> = {}): GitHistoryItem {
|
||||
subject: 'feat: thing',
|
||||
message: 'feat: thing\n\nbody',
|
||||
author: 'Jane',
|
||||
timestamp: NOW / 1000 - 3600,
|
||||
timestamp: NOW - 3_600_000,
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
describe('formatCommitTime', () => {
|
||||
it('formats across thresholds', () => {
|
||||
const s = NOW / 1000
|
||||
expect(formatCommitTime(s - 30, NOW)).toBe('just now')
|
||||
expect(formatCommitTime(s - 5 * 60, NOW)).toBe('5m')
|
||||
expect(formatCommitTime(s - 3 * 3600, NOW)).toBe('3h')
|
||||
expect(formatCommitTime(s - 2 * 86400, NOW)).toBe('2d')
|
||||
expect(formatCommitTime(s - 60 * 86400, NOW)).toBe('2mo')
|
||||
expect(formatCommitTime(s - 800 * 86400, NOW)).toBe('2y')
|
||||
it('formats across thresholds from epoch-millisecond timestamps', () => {
|
||||
// GitHistoryItem.timestamp is epoch ms (git-history-log-parser scales git %at by 1000).
|
||||
const ms = { min: 60_000, hour: 3_600_000, day: 86_400_000 }
|
||||
expect(formatCommitTime(NOW - 3 * ms.hour, NOW)).toBe('3h')
|
||||
expect(formatCommitTime(NOW - 30_000, NOW)).toBe('just now')
|
||||
expect(formatCommitTime(NOW - 5 * ms.min, NOW)).toBe('5m')
|
||||
expect(formatCommitTime(NOW - 2 * ms.day, NOW)).toBe('2d')
|
||||
expect(formatCommitTime(NOW - 60 * ms.day, NOW)).toBe('2mo')
|
||||
expect(formatCommitTime(NOW - 800 * ms.day, NOW)).toBe('2y')
|
||||
})
|
||||
|
||||
it('returns empty for missing timestamp', () => {
|
||||
|
||||
@@ -12,12 +12,13 @@ export type MobileCommitRow = {
|
||||
}
|
||||
|
||||
// Short relative time for a commit list (just now / Xm / Xh / Xd / Xmo / Xy).
|
||||
export function formatCommitTime(timestampSeconds: number | undefined, nowMs: number): string {
|
||||
// `timestampMs` is epoch ms, the unit GitHistoryItem.timestamp already carries.
|
||||
export function formatCommitTime(timestampMs: number | undefined, nowMs: number): string {
|
||||
// Nullish — not falsy — so a real epoch-0 timestamp still formats.
|
||||
if (timestampSeconds == null) {
|
||||
if (timestampMs == null) {
|
||||
return ''
|
||||
}
|
||||
const delta = nowMs - timestampSeconds * 1000
|
||||
const delta = nowMs - timestampMs
|
||||
if (delta < 60_000) {
|
||||
return 'just now'
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ export type GitHistoryItem = {
|
||||
displayId?: string
|
||||
author?: string
|
||||
authorEmail?: string
|
||||
/** Epoch milliseconds (git %at seconds × 1000). */
|
||||
timestamp?: number
|
||||
statistics?: GitHistoryItemStatistics
|
||||
references?: GitHistoryItemRef[]
|
||||
|
||||
@@ -115,7 +115,9 @@ describe('git history parsing', () => {
|
||||
message: 'feat: add graph\n\nbody line',
|
||||
author: 'Ada Lovelace',
|
||||
authorEmail: 'ada@example.com',
|
||||
displayId: HEAD_OID.slice(0, 7)
|
||||
displayId: HEAD_OID.slice(0, 7),
|
||||
// The format feeds %at seconds; consumers get epoch milliseconds.
|
||||
timestamp: 1_700_000_000_000
|
||||
})
|
||||
expect(item?.references?.map((ref) => [ref.id, ref.name, ref.category])).toEqual([
|
||||
['refs/heads/feature', 'feature', 'branches'],
|
||||
|
||||
Reference in New Issue
Block a user