refactor(app): share the compact time-ago prose formatter

Move the tab tooltip's "3m" -> "3m ago" wording into utils/time so the
usage card can reuse it.
This commit is contained in:
Mohamed Boudra
2026-09-27 12:41:40 +02:00
parent 2d63ae0c9d
commit 3b98661281
3 changed files with 22 additions and 7 deletions
@@ -69,6 +69,7 @@ import { RenderProfile } from "@/utils/render-profiler";
import { TrailingActionScrim } from "@/components/ui/trailing-action-scrim";
import { useKeyboardActionHandler } from "@/hooks/use-keyboard-action-handler";
import { useCompactTimeAgo } from "@/hooks/use-compact-time-ago";
import { formatCompactTimeAgoAsProse } from "@/utils/time";
import { buildWorkspaceKeyboardHandlerId } from "@/keyboard/handler-id";
import type { KeyboardActionDefinition } from "@/keyboard/keyboard-action-dispatcher";
import { WorkspaceNewTabMenuContent } from "@/screens/workspace/workspace-new-tab-menu";
@@ -148,12 +149,6 @@ function formatAgentTooltipTitle(singleLineTitle: string): string {
return `${singleLineTitle.slice(0, AGENT_TOOLTIP_TITLE_MAX_LENGTH - 1).trimEnd()}…`;
}
function formatAgentTooltipActivity(compactActivity: string): string {
if (compactActivity === "now") return "just now";
if (/^\d/.test(compactActivity)) return `${compactActivity} ago`;
return compactActivity;
}
function AgentTabTooltipBody({
serverId,
agentId,
@@ -169,7 +164,7 @@ function AgentTabTooltipBody({
return state.agentLastActivity.get(agentId) ?? agent?.lastActivityAt ?? null;
});
const compactActivity = useCompactTimeAgo(lastActivityAt);
const activity = formatAgentTooltipActivity(compactActivity);
const activity = formatCompactTimeAgoAsProse(compactActivity);
return (
<View style={styles.tooltipAgentContent}>
+10
View File
@@ -2,6 +2,7 @@ import { describe, it, expect } from "vitest";
import {
describeCompactTimeAgo,
formatCompactTimeAgo,
formatCompactTimeAgoAsProse,
formatDuration,
formatMessageTimestamp,
formatTimeAgo,
@@ -63,6 +64,15 @@ describe("describeCompactTimeAgo", () => {
});
});
describe("formatCompactTimeAgoAsProse", () => {
it("puts elapsed labels back into prose and leaves dates alone", () => {
expect(formatCompactTimeAgoAsProse("now")).toBe("just now");
expect(formatCompactTimeAgoAsProse("3m")).toBe("3m ago");
expect(formatCompactTimeAgoAsProse("2h")).toBe("2h ago");
expect(formatCompactTimeAgoAsProse("Jan 15")).toBe("Jan 15");
});
});
describe("formatDuration", () => {
it("renders sub-minute durations as whole seconds", () => {
expect(formatDuration(0)).toBe("0s");
+10
View File
@@ -91,6 +91,16 @@ export function formatCompactTimeAgo(date: Date, now: Date = new Date()): string
return describeCompactTimeAgo(date, now).label;
}
/**
* A compact label put back into a sentence, for a tooltip or a line with room for prose:
* "now" → "just now", "5m" → "5m ago", "Jan 15" stays a date.
*/
export function formatCompactTimeAgoAsProse(label: string): string {
if (label === "now") return "just now";
if (/^\d/.test(label)) return `${label} ago`;
return label;
}
/**
* How many local midnights lie between two instants: 0 for the same day, 1 for yesterday.
* Counted on the calendar rather than in elapsed time, so six days and 23 hours ago on