Hide empty Filters section in activity options menu

- Extract visibility logic into reusable hook `useActivityScopeFilterMenuItemsVisible` to avoid duplication
- Only render Filters label and items when filters are available, preventing empty section in dropdown
- Improves UX by not showing unused menu sections
This commit is contained in:
Jinjing
2026-09-08 00:54:34 -07:00
parent 89b9eb4b47
commit b66116280d
2 changed files with 61 additions and 31 deletions
@@ -10,6 +10,24 @@ import {
} from '@/components/sidebar/sidebar-host-options'
import { useSidebarHostScopeOptions } from '@/components/sidebar/use-sidebar-host-scope-options'
/**
* Whether {@link ActivityScopeFilterMenuItems} renders anything.
* Why exported: the parent owns the Filters label and separator, so it has to
* know whether the section would be empty.
*/
export function useActivityScopeFilterMenuItemsVisible(): boolean {
const repos = useAppStore((s) => s.repos)
const agentsVisibleHostIds = useAppStore((s) => s.agentsVisibleHostIds)
const agentsFilterRepoIds = useAppStore((s) => s.agentsFilterRepoIds)
const { hostOptions } = useSidebarHostScopeOptions()
return (
agentsVisibleHostIds !== null ||
agentsFilterRepoIds.length > 0 ||
shouldShowHostScopeControls(hostOptions) ||
repos.length > 1
)
}
/**
* Host/project scope items for the Agents activity surfaces. State is the
* persisted agents-view scope (agentsVisibleHostIds / agentsFilterRepoIds),
@@ -17,7 +35,6 @@ import { useSidebarHostScopeOptions } from '@/components/sidebar/use-sidebar-hos
* Filters label and separator.
*/
export function ActivityScopeFilterMenuItems(): React.JSX.Element | null {
const repos = useAppStore((s) => s.repos)
const agentsVisibleHostIds = useAppStore((s) => s.agentsVisibleHostIds)
const setAgentsVisibleHostIds = useAppStore((s) => s.setAgentsVisibleHostIds)
const agentsFilterRepoIds = useAppStore((s) => s.agentsFilterRepoIds)
@@ -25,8 +42,9 @@ export function ActivityScopeFilterMenuItems(): React.JSX.Element | null {
const { hostOptions } = useSidebarHostScopeOptions()
const showHostScopeControls = shouldShowHostScopeControls(hostOptions)
const hasScopeFilter = agentsVisibleHostIds !== null || agentsFilterRepoIds.length > 0
const visible = useActivityScopeFilterMenuItemsVisible()
if (!hasScopeFilter && !showHostScopeControls && repos.length <= 1) {
if (!visible) {
return null
}
@@ -19,7 +19,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip
import { translate } from '@/i18n/i18n'
import {
ActivityScopeFilterMenuItems,
useActivityScopeFilterActive
useActivityScopeFilterActive,
useActivityScopeFilterMenuItemsVisible
} from './activity-scope-filter-controls'
import type { ActivityGroupBy } from './activity-thread-types'
@@ -79,6 +80,10 @@ export function ActivityThreadOptionsMenu({
}): React.JSX.Element {
const skipCloseAutoFocusRef = React.useRef(false)
const scopeFilterActive = useActivityScopeFilterActive()
const scopeFilterItemsVisible = useActivityScopeFilterMenuItemsVisible()
const hasFilters = Boolean(
onUnreadOnlyChange || onShowChildAgentsChange || scopeFilterItemsVisible
)
const optionsLabel = scopeFilterActive
? translate(
'auto.components.activity.ActivityPrototypePage.threadListOptionsFiltered',
@@ -131,35 +136,42 @@ export function ActivityThreadOptionsMenu({
}
}}
>
<DropdownMenuLabel>
{translate('auto.components.activity.ActivityPrototypePage.filtersSection', 'Filters')}
</DropdownMenuLabel>
{onUnreadOnlyChange ? (
<DropdownMenuCheckboxItem
checked={unreadOnly}
onCheckedChange={(checked) => onUnreadOnlyChange(checked === true)}
onSelect={(event) => event.preventDefault()}
>
{translate(
'auto.components.activity.ActivityPrototypePage.showUnreadOnly',
'Show unread only'
)}
</DropdownMenuCheckboxItem>
{hasFilters ? (
<>
<DropdownMenuLabel>
{translate(
'auto.components.activity.ActivityPrototypePage.filtersSection',
'Filters'
)}
</DropdownMenuLabel>
{onUnreadOnlyChange ? (
<DropdownMenuCheckboxItem
checked={unreadOnly}
onCheckedChange={(checked) => onUnreadOnlyChange(checked === true)}
onSelect={(event) => event.preventDefault()}
>
{translate(
'auto.components.activity.ActivityPrototypePage.showUnreadOnly',
'Show unread only'
)}
</DropdownMenuCheckboxItem>
) : null}
{onShowChildAgentsChange ? (
<DropdownMenuCheckboxItem
checked={showChildAgents}
onCheckedChange={(checked) => onShowChildAgentsChange(checked === true)}
onSelect={(event) => event.preventDefault()}
>
{translate(
'auto.components.activity.ActivityPrototypePage.showChildAgents',
'Show child agents'
)}
</DropdownMenuCheckboxItem>
) : null}
<ActivityScopeFilterMenuItems />
<DropdownMenuSeparator />
</>
) : null}
{onShowChildAgentsChange ? (
<DropdownMenuCheckboxItem
checked={showChildAgents}
onCheckedChange={(checked) => onShowChildAgentsChange(checked === true)}
onSelect={(event) => event.preventDefault()}
>
{translate(
'auto.components.activity.ActivityPrototypePage.showChildAgents',
'Show child agents'
)}
</DropdownMenuCheckboxItem>
) : null}
<ActivityScopeFilterMenuItems />
<DropdownMenuSeparator />
<DropdownMenuLabel>
{translate('auto.components.activity.ActivityPrototypePage.viewSection', 'View')}
</DropdownMenuLabel>