fix(desktop): remove activity count badge

Keep the Activity entry available without showing persistent numeric attention markers.

Confidence: high
Scope-risk: narrow
Tested: bun run check:desktop
Not-tested: manual Electron visual smoke
This commit is contained in:
程序员阿江(Relakkes) 2026-07-10 18:05:54 +08:00
parent 899ec2c3b4
commit 745112a136
3 changed files with 11 additions and 25 deletions

View File

@ -4,21 +4,17 @@ import { useActivityPanelStore } from '../../stores/activityPanelStore'
type SessionActivityButtonProps = {
sessionId: string
badgeCount: number
label?: string
}
export function SessionActivityButton({
sessionId,
badgeCount,
label,
}: SessionActivityButtonProps) {
const t = useTranslation()
const resolvedLabel = label ?? t('session.activity.title')
const isOpen = useActivityPanelStore((state) => state.isOpen(sessionId))
const toggle = useActivityPanelStore((state) => state.toggle)
const visibleBadgeCount = Math.max(0, badgeCount)
return (
<button
type="button"
@ -36,14 +32,6 @@ export function SessionActivityButton({
}`}
>
<ListChecks size={17} strokeWidth={1.9} />
{visibleBadgeCount > 0 && (
<span
data-testid="session-activity-badge"
className="absolute -right-1 -top-1 inline-flex min-w-4 h-4 items-center justify-center rounded-full bg-[var(--color-error)] px-1 text-[10px] font-semibold leading-none text-white"
>
{visibleBadgeCount > 9 ? '9+' : visibleBadgeCount}
</span>
)}
</button>
)
}

View File

@ -326,7 +326,7 @@ describe('TabBar', () => {
expect(screen.queryByTestId('session-activity-badge')).not.toBeInTheDocument()
})
it('shows the activity button with a badge for running or failed activity', async () => {
it('shows the activity button without a numeric badge for running or failed activity', async () => {
const { TabBar } = await import('./TabBar')
const { useTabStore } = await import('../../stores/tabStore')
const { useChatStore } = await import('../../stores/chatStore')
@ -375,7 +375,7 @@ describe('TabBar', () => {
const button = screen.getByRole('button', { name: /activity/i })
expect(button).toBeInTheDocument()
expect(screen.getByTestId('session-activity-badge')).toHaveTextContent('2')
expect(screen.queryByTestId('session-activity-badge')).not.toBeInTheDocument()
expect(useActivityPanelStore.getState().isOpen(sessionId)).toBe(false)
expect(button).toHaveAttribute('aria-expanded', 'false')
expect(button).toHaveAttribute('aria-pressed', 'false')
@ -426,7 +426,7 @@ describe('TabBar', () => {
})
expect(screen.getByRole('button', { name: /activity/i })).toBeInTheDocument()
expect(screen.getByTestId('session-activity-badge')).toHaveTextContent('1')
expect(screen.queryByTestId('session-activity-badge')).not.toBeInTheDocument()
})
it('hides team-only activity when the active team belongs to another session', async () => {
@ -469,7 +469,7 @@ describe('TabBar', () => {
expect(screen.queryByTestId('session-activity-badge')).not.toBeInTheDocument()
})
it('shows the activity button when team activity arrives after initial render', async () => {
it('shows the activity button without a badge when team activity arrives after initial render', async () => {
const { TabBar } = await import('./TabBar')
const { useTabStore } = await import('../../stores/tabStore')
const { useChatStore } = await import('../../stores/chatStore')
@ -511,7 +511,7 @@ describe('TabBar', () => {
})
expect(screen.getByRole('button', { name: /activity/i })).toBeInTheDocument()
expect(screen.getByTestId('session-activity-badge')).toHaveTextContent('1')
expect(screen.queryByTestId('session-activity-badge')).not.toBeInTheDocument()
})
it('does not show the activity button for settings tabs', async () => {
@ -530,7 +530,7 @@ describe('TabBar', () => {
expect(screen.queryByRole('button', { name: /activity/i })).not.toBeInTheDocument()
})
it('includes current-session CLI tasks in the activity badge', async () => {
it('shows current-session CLI tasks without a numeric activity badge', async () => {
const { TabBar } = await import('./TabBar')
const { useTabStore } = await import('../../stores/tabStore')
const { useChatStore } = await import('../../stores/chatStore')
@ -580,10 +580,10 @@ describe('TabBar', () => {
render(<TabBar />)
})
expect(screen.getByTestId('session-activity-badge')).toHaveTextContent('2')
expect(screen.queryByTestId('session-activity-badge')).not.toBeInTheDocument()
})
it('excludes dismissed failed background tasks from the activity badge while keeping running tasks', async () => {
it('keeps running activity available without showing a numeric badge', async () => {
const { TabBar } = await import('./TabBar')
const { useTabStore } = await import('../../stores/tabStore')
const { useChatStore } = await import('../../stores/chatStore')
@ -636,7 +636,7 @@ describe('TabBar', () => {
render(<TabBar />)
})
expect(screen.getByTestId('session-activity-badge')).toHaveTextContent('1')
expect(screen.queryByTestId('session-activity-badge')).not.toBeInTheDocument()
})
it('ignores CLI tasks from a different session in the activity badge', async () => {

View File

@ -122,7 +122,7 @@ export function TabBar() {
}))
const activityState = useChatStore(useShallow((state) => {
if (!activeTabId || !isActiveSessionTab) {
return { badgeCount: 0, hasVisibleActivity: false }
return { hasVisibleActivity: false }
}
const sessionState = state.sessions[activeTabId]
const includeCliTasks = cliTasksSessionId === activeTabId
@ -138,12 +138,10 @@ export function TabBar() {
teamMembers: activityTeamMembers,
})
return {
badgeCount: model.badgeCount,
hasVisibleActivity: hasVisibleSessionActivity(model),
}
}))
const showActivityButton = activeTabId && activityState.hasVisibleActivity
const activityBadgeCount = activityState.badgeCount
const moveTab = useTabStore((s) => s.moveTab)
const scrollRef = useRef<HTMLDivElement>(null)
@ -435,7 +433,7 @@ export function TabBar() {
<div className="flex shrink-0 items-center gap-1 border-l border-[var(--color-border)]/70 px-2">
{showActivityButton && activeTabId && (
<SessionActivityButton sessionId={activeTabId} badgeCount={activityBadgeCount} />
<SessionActivityButton sessionId={activeTabId} />
)}
{isDesktopRuntime && isActiveSessionTab && (
<OpenProjectMenu path={openProjectPath} />