compact long subagent durations
This commit is contained in:
12 files changed
+136
-31
No files matched your search
@@ -76,16 +76,54 @@ function activityDuration(
|
||||
return timing.settledMs + Math.max(0, end - timing.active.since)
|
||||
}
|
||||
|
||||
/** Format a non-negative duration to seconds without dropping larger units. */
|
||||
function formatDuration(ms: number, t: TranslateNS<typeof NS>): string {
|
||||
interface DurationParts {
|
||||
seconds: number
|
||||
minutes: number
|
||||
hours: number
|
||||
days: number
|
||||
totalMinutes: number
|
||||
totalHours: number
|
||||
}
|
||||
|
||||
function splitDuration(ms: number): DurationParts {
|
||||
const totalSeconds = Math.floor(Math.max(0, ms) / 1_000)
|
||||
const seconds = totalSeconds % 60
|
||||
const totalMinutes = Math.floor(totalSeconds / 60)
|
||||
const minutes = totalMinutes % 60
|
||||
const hours = Math.floor(totalMinutes / 60)
|
||||
if (hours > 0) {
|
||||
const totalHours = Math.floor(totalMinutes / 60)
|
||||
return {
|
||||
seconds: totalSeconds % 60,
|
||||
minutes: totalMinutes % 60,
|
||||
hours: totalHours % 24,
|
||||
days: Math.floor(totalHours / 24),
|
||||
totalMinutes,
|
||||
totalHours,
|
||||
}
|
||||
}
|
||||
|
||||
/** Format a duration with decreasing visual precision at larger scales. */
|
||||
function formatDuration(ms: number, t: TranslateNS<typeof NS>): string {
|
||||
const { seconds, minutes, hours, days, totalMinutes, totalHours } = splitDuration(ms)
|
||||
if (days >= 365) {
|
||||
const years = Math.floor(days / 365)
|
||||
const months = Math.floor((days % 365) / 30)
|
||||
return months === 0
|
||||
? t('duration.years', { years })
|
||||
: t('duration.yearsMonths', { years, months })
|
||||
}
|
||||
if (days >= 30) {
|
||||
const months = Math.floor(days / 30)
|
||||
const remainingDays = days % 30
|
||||
return remainingDays === 0
|
||||
? t('duration.months', { months })
|
||||
: t('duration.monthsDays', { months, days: remainingDays })
|
||||
}
|
||||
if (days > 0) {
|
||||
return hours === 0
|
||||
? t('duration.days', { days })
|
||||
: t('duration.daysHours', { days, hours })
|
||||
}
|
||||
if (totalHours > 0) {
|
||||
return t('duration.hours', {
|
||||
hours,
|
||||
hours: totalHours,
|
||||
minutes: String(minutes).padStart(2, '0'),
|
||||
seconds: String(seconds).padStart(2, '0'),
|
||||
})
|
||||
@@ -99,6 +137,19 @@ function formatDuration(ms: number, t: TranslateNS<typeof NS>): string {
|
||||
return t('duration.seconds', { seconds })
|
||||
}
|
||||
|
||||
/** Preserve exact whole seconds for hover and accessible naming. */
|
||||
function formatExactDuration(ms: number, t: TranslateNS<typeof NS>): string {
|
||||
const { seconds, minutes, hours, days } = splitDuration(ms)
|
||||
return days === 0
|
||||
? formatDuration(ms, t)
|
||||
: t('duration.exactDays', {
|
||||
days,
|
||||
hours: String(hours).padStart(2, '0'),
|
||||
minutes: String(minutes).padStart(2, '0'),
|
||||
seconds: String(seconds).padStart(2, '0'),
|
||||
})
|
||||
}
|
||||
|
||||
/** Aggregate the complete subagent-only descendant subtree from flat summaries. */
|
||||
function summarizeDescendants(
|
||||
sessionId: SessionId,
|
||||
@@ -231,7 +282,10 @@ function CatalogRows({
|
||||
)
|
||||
const duration = durationMs === undefined
|
||||
? undefined
|
||||
: formatDuration(durationMs, t)
|
||||
: {
|
||||
compact: formatDuration(durationMs, t),
|
||||
exact: formatExactDuration(durationMs, t),
|
||||
}
|
||||
|
||||
const open = (): void => {
|
||||
openChild({ parentSessionId, childSessionId: entry.id, mode: entry.mode })
|
||||
@@ -263,7 +317,7 @@ function CatalogRows({
|
||||
role="treeitem"
|
||||
tabIndex={0}
|
||||
aria-level={level}
|
||||
aria-label={[label, secondary, duration]
|
||||
aria-label={[label, secondary, duration?.exact]
|
||||
.filter(value => value !== undefined)
|
||||
.join(' ')}
|
||||
{...knownLeaf ? {} : { 'aria-expanded': isExpanded }}
|
||||
@@ -290,7 +344,14 @@ function CatalogRows({
|
||||
<span className={css.label}>{label}</span>
|
||||
<span className={css.summary}>{secondary}</span>
|
||||
</span>
|
||||
{duration !== undefined && <span className={css.time}>{duration}</span>}
|
||||
{duration !== undefined && (
|
||||
<span
|
||||
className={css.time}
|
||||
title={t('duration.exactTitle', { duration: duration.exact })}
|
||||
>
|
||||
{duration.compact}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{isExpanded && !knownLeaf && (
|
||||
|
||||
@@ -11,6 +11,14 @@ export const zh = {
|
||||
'duration.seconds': '{seconds}秒',
|
||||
'duration.minutes': '{minutes}分{seconds}秒',
|
||||
'duration.hours': '{hours}小时{minutes}分{seconds}秒',
|
||||
'duration.days': '{days}天',
|
||||
'duration.daysHours': '{days}天{hours}小时',
|
||||
'duration.months': '约{months}个月',
|
||||
'duration.monthsDays': '约{months}个月{days}天',
|
||||
'duration.years': '约{years}年',
|
||||
'duration.yearsMonths': '约{years}年{months}个月',
|
||||
'duration.exactDays': '{days}天{hours}小时{minutes}分{seconds}秒',
|
||||
'duration.exactTitle': '总活跃耗时:{duration}',
|
||||
'loading.label': '正在加载子代理…',
|
||||
'loading.aria': '正在加载子代理',
|
||||
'load.error': '无法加载子代理',
|
||||
@@ -40,6 +48,14 @@ export const en: Record<SubagentKey, string> = {
|
||||
'duration.seconds': '{seconds}s',
|
||||
'duration.minutes': '{minutes}m {seconds}s',
|
||||
'duration.hours': '{hours}h {minutes}m {seconds}s',
|
||||
'duration.days': '{days}d',
|
||||
'duration.daysHours': '{days}d {hours}h',
|
||||
'duration.months': '~{months}mo',
|
||||
'duration.monthsDays': '~{months}mo {days}d',
|
||||
'duration.years': '~{years}y',
|
||||
'duration.yearsMonths': '~{years}y {months}mo',
|
||||
'duration.exactDays': '{days}d {hours}h {minutes}m {seconds}s',
|
||||
'duration.exactTitle': 'Total active duration: {duration}',
|
||||
'loading.label': 'Loading subagents…',
|
||||
'loading.aria': 'Loading subagents',
|
||||
'load.error': 'Unable to load subagents',
|
||||
|
||||
Reference in New Issue
Block a user