Compare commits

...

1 Commits

Author SHA1 Message Date
Jiang Bohan
889b7d1ab0 fix(issues): hide activity-block header while only recent entries are shown
In the trailing activity block's default truncated state ("last 8 shown,
N older hidden"), we were rendering two stacked chevron rows: a "v N
activities" collapse header and a "> Show N more activities" reveal link.
Visually that looked like nested folds even though they're parallel
controls, and the header is redundant when the user just wants a glance
at recent activity.

Drop the header in the truncated default state. It reappears the moment
the user clicks "Show N more" — at that point they're seeing the full
block and a fold-back affordance becomes useful again. Blocks that fit
within the 8-entry limit (and non-trailing blocks, which never truncate)
keep their header as before.
2026-05-25 18:57:11 +08:00
2 changed files with 26 additions and 17 deletions

View File

@@ -865,10 +865,13 @@ describe("IssueDetail (shared)", () => {
renderIssueDetail();
// The block header reports the full count.
// In the truncated default state the "N activities" collapse header
// stays hidden — the "Show N more" link is the only control we want
// to expose for a glance at recent activity.
await waitFor(() => {
expect(screen.getByText("10 activities")).toBeInTheDocument();
expect(screen.getByText("Show 2 more activities")).toBeInTheDocument();
});
expect(screen.queryByText("10 activities")).not.toBeInTheDocument();
// Only the 8 most recent entries (act-3..act-10) are rendered by default.
// act-1 and act-2 are folded behind the show-more line.
@@ -877,18 +880,15 @@ describe("IssueDetail (shared)", () => {
expect(screen.queryByText(/from Todo to In Progress/i)).not.toBeInTheDocument(); // act-1
expect(screen.queryByText(/from Low to Medium/i)).not.toBeInTheDocument(); // act-2
// The show-more toggle reports the count of hidden older entries (2).
const showMore = screen.getByText("Show 2 more activities");
expect(showMore).toBeInTheDocument();
// Clicking the toggle reveals the older entries in place; the rest of the
// block stays visible.
fireEvent.click(showMore);
// Clicking the toggle reveals the older entries in place and brings the
// full "N activities" header back (so the user can fold the block).
fireEvent.click(screen.getByText("Show 2 more activities"));
await waitFor(() => {
expect(screen.getByText(/from Todo to In Progress/i)).toBeInTheDocument();
});
expect(screen.getByText(/from Low to Medium/i)).toBeInTheDocument();
expect(screen.getByText(/set due date to/i)).toBeInTheDocument();
expect(screen.getByText("10 activities")).toBeInTheDocument();
expect(screen.queryByText(/Show \d+ more activit/i)).not.toBeInTheDocument();
});

View File

@@ -442,16 +442,25 @@ function ActivityBlock({
: 0;
const visibleEntries =
hiddenOlderCount > 0 ? entries.slice(-LAST_ACTIVITY_BLOCK_VISIBLE_LIMIT) : entries;
// Hide the "v N activities" collapse header while we're in the truncated
// default state. The "Show N more" link is the only control users need
// when they're glancing at recent activity — stacking two chevron rows
// looked like nested folds and added visual noise without value. Once the
// user explicitly reveals older entries, the header reappears so they can
// fold the whole block back to a single count line.
const showHeader = hiddenOlderCount === 0;
return (
<div className="pb-3 px-4 flex flex-col gap-3">
<button
type="button"
onClick={onToggle}
className="flex items-center gap-1.5 text-xs text-muted-foreground transition-colors hover:text-foreground"
>
<ChevronDown className="h-3 w-3 shrink-0" />
<span>{t(($) => $.activity.activity_count, { count: entries.length })}</span>
</button>
{showHeader && (
<button
type="button"
onClick={onToggle}
className="flex items-center gap-1.5 text-xs text-muted-foreground transition-colors hover:text-foreground"
>
<ChevronDown className="h-3 w-3 shrink-0" />
<span>{t(($) => $.activity.activity_count, { count: entries.length })}</span>
</button>
)}
{hiddenOlderCount > 0 && (
<button
type="button"