mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-08-01 16:43:37 +08:00
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:
parent
899ec2c3b4
commit
745112a136
@ -4,21 +4,17 @@ import { useActivityPanelStore } from '../../stores/activityPanelStore'
|
|||||||
|
|
||||||
type SessionActivityButtonProps = {
|
type SessionActivityButtonProps = {
|
||||||
sessionId: string
|
sessionId: string
|
||||||
badgeCount: number
|
|
||||||
label?: string
|
label?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SessionActivityButton({
|
export function SessionActivityButton({
|
||||||
sessionId,
|
sessionId,
|
||||||
badgeCount,
|
|
||||||
label,
|
label,
|
||||||
}: SessionActivityButtonProps) {
|
}: SessionActivityButtonProps) {
|
||||||
const t = useTranslation()
|
const t = useTranslation()
|
||||||
const resolvedLabel = label ?? t('session.activity.title')
|
const resolvedLabel = label ?? t('session.activity.title')
|
||||||
const isOpen = useActivityPanelStore((state) => state.isOpen(sessionId))
|
const isOpen = useActivityPanelStore((state) => state.isOpen(sessionId))
|
||||||
const toggle = useActivityPanelStore((state) => state.toggle)
|
const toggle = useActivityPanelStore((state) => state.toggle)
|
||||||
const visibleBadgeCount = Math.max(0, badgeCount)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@ -36,14 +32,6 @@ export function SessionActivityButton({
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<ListChecks size={17} strokeWidth={1.9} />
|
<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>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -326,7 +326,7 @@ describe('TabBar', () => {
|
|||||||
expect(screen.queryByTestId('session-activity-badge')).not.toBeInTheDocument()
|
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 { TabBar } = await import('./TabBar')
|
||||||
const { useTabStore } = await import('../../stores/tabStore')
|
const { useTabStore } = await import('../../stores/tabStore')
|
||||||
const { useChatStore } = await import('../../stores/chatStore')
|
const { useChatStore } = await import('../../stores/chatStore')
|
||||||
@ -375,7 +375,7 @@ describe('TabBar', () => {
|
|||||||
|
|
||||||
const button = screen.getByRole('button', { name: /activity/i })
|
const button = screen.getByRole('button', { name: /activity/i })
|
||||||
expect(button).toBeInTheDocument()
|
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(useActivityPanelStore.getState().isOpen(sessionId)).toBe(false)
|
||||||
expect(button).toHaveAttribute('aria-expanded', 'false')
|
expect(button).toHaveAttribute('aria-expanded', 'false')
|
||||||
expect(button).toHaveAttribute('aria-pressed', 'false')
|
expect(button).toHaveAttribute('aria-pressed', 'false')
|
||||||
@ -426,7 +426,7 @@ describe('TabBar', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
expect(screen.getByRole('button', { name: /activity/i })).toBeInTheDocument()
|
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 () => {
|
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()
|
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 { TabBar } = await import('./TabBar')
|
||||||
const { useTabStore } = await import('../../stores/tabStore')
|
const { useTabStore } = await import('../../stores/tabStore')
|
||||||
const { useChatStore } = await import('../../stores/chatStore')
|
const { useChatStore } = await import('../../stores/chatStore')
|
||||||
@ -511,7 +511,7 @@ describe('TabBar', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
expect(screen.getByRole('button', { name: /activity/i })).toBeInTheDocument()
|
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 () => {
|
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()
|
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 { TabBar } = await import('./TabBar')
|
||||||
const { useTabStore } = await import('../../stores/tabStore')
|
const { useTabStore } = await import('../../stores/tabStore')
|
||||||
const { useChatStore } = await import('../../stores/chatStore')
|
const { useChatStore } = await import('../../stores/chatStore')
|
||||||
@ -580,10 +580,10 @@ describe('TabBar', () => {
|
|||||||
render(<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 { TabBar } = await import('./TabBar')
|
||||||
const { useTabStore } = await import('../../stores/tabStore')
|
const { useTabStore } = await import('../../stores/tabStore')
|
||||||
const { useChatStore } = await import('../../stores/chatStore')
|
const { useChatStore } = await import('../../stores/chatStore')
|
||||||
@ -636,7 +636,7 @@ describe('TabBar', () => {
|
|||||||
render(<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 () => {
|
it('ignores CLI tasks from a different session in the activity badge', async () => {
|
||||||
|
|||||||
@ -122,7 +122,7 @@ export function TabBar() {
|
|||||||
}))
|
}))
|
||||||
const activityState = useChatStore(useShallow((state) => {
|
const activityState = useChatStore(useShallow((state) => {
|
||||||
if (!activeTabId || !isActiveSessionTab) {
|
if (!activeTabId || !isActiveSessionTab) {
|
||||||
return { badgeCount: 0, hasVisibleActivity: false }
|
return { hasVisibleActivity: false }
|
||||||
}
|
}
|
||||||
const sessionState = state.sessions[activeTabId]
|
const sessionState = state.sessions[activeTabId]
|
||||||
const includeCliTasks = cliTasksSessionId === activeTabId
|
const includeCliTasks = cliTasksSessionId === activeTabId
|
||||||
@ -138,12 +138,10 @@ export function TabBar() {
|
|||||||
teamMembers: activityTeamMembers,
|
teamMembers: activityTeamMembers,
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
badgeCount: model.badgeCount,
|
|
||||||
hasVisibleActivity: hasVisibleSessionActivity(model),
|
hasVisibleActivity: hasVisibleSessionActivity(model),
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
const showActivityButton = activeTabId && activityState.hasVisibleActivity
|
const showActivityButton = activeTabId && activityState.hasVisibleActivity
|
||||||
const activityBadgeCount = activityState.badgeCount
|
|
||||||
|
|
||||||
const moveTab = useTabStore((s) => s.moveTab)
|
const moveTab = useTabStore((s) => s.moveTab)
|
||||||
const scrollRef = useRef<HTMLDivElement>(null)
|
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">
|
<div className="flex shrink-0 items-center gap-1 border-l border-[var(--color-border)]/70 px-2">
|
||||||
{showActivityButton && activeTabId && (
|
{showActivityButton && activeTabId && (
|
||||||
<SessionActivityButton sessionId={activeTabId} badgeCount={activityBadgeCount} />
|
<SessionActivityButton sessionId={activeTabId} />
|
||||||
)}
|
)}
|
||||||
{isDesktopRuntime && isActiveSessionTab && (
|
{isDesktopRuntime && isActiveSessionTab && (
|
||||||
<OpenProjectMenu path={openProjectPath} />
|
<OpenProjectMenu path={openProjectPath} />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user