feat(sidebar): show compact timestamp in recent activity rows
The sidebar's recent activity list (SidebarActivitySections) rendered its session rows without an inline timestamp on web/desktop — the compact relative label only appeared in the hover tooltip and on touch runtimes. Render the existing i18n-backed formatSessionCompactDateLabel inline in the recent rows' metadata slot, alongside the goal/branch glyphs, for web/desktop too. It keeps the same hover-fade as the other metadata, so the hover-revealed row actions never overlap it, and the full date stays available in the row tooltip. No new strings: the label reuses common.relative.* keys. Fixes #2560
This commit is contained in:
@@ -0,0 +1,41 @@
|
|||||||
|
import { describe, expect, test } from 'bun:test';
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
|
||||||
|
const source = readFileSync(new URL('./SessionNodeItem.tsx', import.meta.url), 'utf8');
|
||||||
|
|
||||||
|
describe('SessionNodeItem recent-activity timestamp', () => {
|
||||||
|
test('the recent activity rows render the compact timestamp in the inline metadata slot', () => {
|
||||||
|
// The right-slot guard must open for recent rows even when no activity,
|
||||||
|
// goal glyph, or branch marker is present.
|
||||||
|
const guard = source.indexOf("showActivityDuration || sessionGoalGlyph || showInlineBranchMarker || renderContext === 'recent'");
|
||||||
|
expect(guard).toBeGreaterThan(-1);
|
||||||
|
// The recent-only block sits inside that slot…
|
||||||
|
const guardOpen = source.indexOf("{renderContext === 'recent' ? (", guard);
|
||||||
|
expect(guardOpen).toBeGreaterThan(guard);
|
||||||
|
// …and the compact label rendered there is the first one after it.
|
||||||
|
const label = source.indexOf('{sessionCompactUpdatedLabel}', guardOpen);
|
||||||
|
expect(label).toBeGreaterThan(guardOpen);
|
||||||
|
// The only later occurrence is the pre-existing row tooltip (which shows
|
||||||
|
// the full date), not a second inline render.
|
||||||
|
const tooltipLabel = source.indexOf('{sessionCompactUpdatedLabel}', label + 1);
|
||||||
|
expect(tooltipLabel).toBeGreaterThan(label);
|
||||||
|
expect(source.indexOf('title={sessionUpdatedLabel}', tooltipLabel - 80)).toBeGreaterThan(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the timestamp shares the hover-fade of the other metadata so revealed actions never overlap it', () => {
|
||||||
|
const guard = source.indexOf("showActivityDuration || sessionGoalGlyph || showInlineBranchMarker || renderContext === 'recent'");
|
||||||
|
// The slot content fades out while the row is hovered (hideOnHoverClass)
|
||||||
|
// and while the row menu is open — the same span that now carries the
|
||||||
|
// recent timestamp.
|
||||||
|
const hideOnHover = source.indexOf('hideOnHoverClass', guard);
|
||||||
|
expect(hideOnHover).toBeGreaterThan(guard);
|
||||||
|
expect(hideOnHover).toBeLessThan(source.indexOf("{renderContext === 'recent' ? (", guard));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the compact label uses the existing i18n-backed relative time helper', () => {
|
||||||
|
// formatSessionCompactDateLabel (already used by touch runtimes and the
|
||||||
|
// row tooltip) is the source of the label — no new formatting code.
|
||||||
|
expect(source.indexOf('const sessionCompactUpdatedLabel = formatSessionCompactDateLabel(sessionTimestamp);')).toBeGreaterThan(-1);
|
||||||
|
expect(source.indexOf('{sessionCompactUpdatedLabel}')).toBeGreaterThan(-1);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1257,7 +1257,7 @@ function SessionNodeItemComponent(props: Props): React.ReactNode {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
) : (showActivityDuration || sessionGoalGlyph || showInlineBranchMarker) ? (
|
) : (showActivityDuration || sessionGoalGlyph || showInlineBranchMarker || renderContext === 'recent') ? (
|
||||||
<div className="relative ml-1 flex h-4 flex-shrink-0 items-center justify-end">
|
<div className="relative ml-1 flex h-4 flex-shrink-0 items-center justify-end">
|
||||||
<span className={cn(
|
<span className={cn(
|
||||||
'inline-flex items-center gap-1 whitespace-nowrap text-right transition-opacity duration-150',
|
'inline-flex items-center gap-1 whitespace-nowrap text-right transition-opacity duration-150',
|
||||||
@@ -1281,6 +1281,18 @@ function SessionNodeItemComponent(props: Props): React.ReactNode {
|
|||||||
style={prIconColor ? { color: prIconColor } : undefined}
|
style={prIconColor ? { color: prIconColor } : undefined}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
{/* The recent activity list shows its compact
|
||||||
|
timestamp inline (touch runtimes already get
|
||||||
|
it through the alwaysShowActions branch);
|
||||||
|
it shares the slot with the goal/branch
|
||||||
|
metadata and hides on hover exactly like
|
||||||
|
them, so the revealed row actions never
|
||||||
|
overlap it. */}
|
||||||
|
{renderContext === 'recent' ? (
|
||||||
|
<span className="flex-shrink-0 text-[0.72rem] leading-none text-muted-foreground/75 tabular-nums">
|
||||||
|
{sessionCompactUpdatedLabel}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user