fix: simplify task center status selection and rendering
This commit is contained in:
@@ -363,6 +363,7 @@ describe('RightAssistantSidebar resizing', () => {
|
||||
}
|
||||
const view = render(sidebarElement(props))
|
||||
fireEvent.click(screen.getByRole('button', { name: '项目任务 2' }))
|
||||
fireEvent.click(screen.getByRole('button', { name: '全部' }))
|
||||
const stats = within(screen.getByRole('region', { name: '当前会话统计' }))
|
||||
expect(stats.getByText('01:01:01')).toBeVisible()
|
||||
expect(stats.getByText('24')).toBeVisible()
|
||||
@@ -385,29 +386,22 @@ describe('RightAssistantSidebar resizing', () => {
|
||||
for (const task of tasks) expect(screen.queryByText(task.title)).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('keeps an applied filter visible when collapsed and clears it without opening the filter panel', () => {
|
||||
it('shows the task status tabs when expanded and defaults to active tasks', () => {
|
||||
renderSidebar({ tasks: [{
|
||||
id: 'completed', projectId: currentProject.id, title: 'Completed task', instructions: '',
|
||||
origin: 'schedule', status: 'completed', createdAt: '2026-09-17T00:00:00Z'
|
||||
}] })
|
||||
const toggle = screen.getByRole('button', { name: '筛选任务' })
|
||||
expect(screen.getByText('Completed task')).toBeVisible()
|
||||
fireEvent.click(toggle)
|
||||
fireEvent.click(screen.getByRole('button', { name: '进行中' }))
|
||||
fireEvent.click(toggle)
|
||||
expect(toggle).toHaveAttribute('aria-expanded', 'false')
|
||||
expect(toggle).toHaveAttribute('data-active', 'true')
|
||||
expect(screen.queryByRole('group', { name: '筛选任务' })).not.toBeInTheDocument()
|
||||
expect(screen.getByText('筛选:进行中 · 0 项')).toBeVisible()
|
||||
expect(screen.getByText('当前筛选条件下没有任务。')).toBeVisible()
|
||||
fireEvent.click(screen.getByRole('button', { name: '清除筛选' }))
|
||||
expect(toggle).toHaveAttribute('data-active', 'false')
|
||||
expect(screen.queryByText('Completed task')).not.toBeInTheDocument()
|
||||
expect(screen.queryByRole('button', { name: '筛选任务' })).not.toBeInTheDocument()
|
||||
const filters = within(screen.getByRole('group', { name: '筛选任务' }))
|
||||
expect(filters.getByRole('button', { name: '进行中' })).toHaveAttribute('aria-pressed', 'true')
|
||||
expect(screen.queryByText('Completed task')).not.toBeInTheDocument()
|
||||
fireEvent.click(filters.getByRole('button', { name: '已结束' }))
|
||||
expect(screen.getByText('Completed task')).toBeVisible()
|
||||
})
|
||||
|
||||
it('scrolls the focused task filter into view when keyboard navigation reaches either end', () => {
|
||||
renderSidebar()
|
||||
fireEvent.click(screen.getByRole('button', { name: '筛选任务' }))
|
||||
const filters = within(screen.getByRole('group', { name: '筛选任务' }))
|
||||
const first = filters.getByRole('button', { name: '全部' })
|
||||
const last = filters.getByRole('button', { name: '已结束' })
|
||||
@@ -658,7 +652,7 @@ describe('RightAssistantSidebar resizing', () => {
|
||||
expect(list).toBeVisible()
|
||||
fireEvent.click(toggle)
|
||||
expect(list).not.toBeVisible()
|
||||
fireEvent.click(screen.getByRole('button', { name: '筛选任务' }))
|
||||
fireEvent.click(toggle)
|
||||
expect(toggle).toHaveAttribute('aria-expanded', 'true')
|
||||
expect(list).toBeVisible()
|
||||
})
|
||||
@@ -676,7 +670,7 @@ describe('RightAssistantSidebar resizing', () => {
|
||||
expect(within(stats).getByText(`项目:${currentProject.name}`)).toBeVisible()
|
||||
expect(screen.getByRole('button', { name: '项目任务 4' })).toHaveAttribute('aria-expanded', 'false')
|
||||
expect(screen.getByText('2 运行中')).toBeVisible()
|
||||
fireEvent.click(screen.getByRole('button', { name: '筛选任务' }))
|
||||
fireEvent.click(screen.getByRole('button', { name: '项目任务 4' }))
|
||||
fireEvent.click(within(screen.getByRole('group', { name: '筛选任务' })).getByRole('button', { name: '已结束' }))
|
||||
expect(screen.getByText('2 运行中')).toBeVisible()
|
||||
view.rerender(sidebarElement({ tab: 'tasks', tasks: [] }))
|
||||
@@ -701,10 +695,7 @@ describe('RightAssistantSidebar resizing', () => {
|
||||
)
|
||||
fireEvent.click(newTaskButton)
|
||||
expect(onCreateCustomTask).toHaveBeenCalledOnce()
|
||||
expect(
|
||||
screen.queryByRole('group', { name: '筛选任务' })
|
||||
).not.toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: '筛选任务' })).toHaveAttribute('aria-expanded', 'false')
|
||||
expect(screen.getByRole('group', { name: '筛选任务' })).toBeVisible()
|
||||
expect(screen.queryByLabelText('定时任务标题')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('最近任务')).not.toBeInTheDocument()
|
||||
})
|
||||
@@ -736,7 +727,6 @@ describe('RightAssistantSidebar resizing', () => {
|
||||
approvals: [approval], onOpenTask, onRespondApproval
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '筛选任务' }))
|
||||
const filters = within(screen.getByRole('group', { name: '筛选任务' }))
|
||||
expect(filters.getAllByRole('button').map((button) => button.textContent))
|
||||
.toEqual(['全部', '进行中', '暂停', '已结束'])
|
||||
@@ -782,7 +772,6 @@ describe('RightAssistantSidebar resizing', () => {
|
||||
}
|
||||
const onRespondApproval = vi.fn()
|
||||
renderSidebar({ tasks: [task], approvals: [approval], onRespondApproval })
|
||||
fireEvent.click(screen.getByRole('button', { name: '筛选任务' }))
|
||||
const row = screen.getByText(task.title).closest('article')!
|
||||
expect(within(row).getByLabelText('等待审批: Confirm write')).toBeVisible()
|
||||
expect(screen.queryByRole('heading', { name: '等待审批' })).not.toBeInTheDocument()
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
Copy,
|
||||
ExternalLink,
|
||||
FileText,
|
||||
Filter,
|
||||
Maximize2,
|
||||
Minimize2,
|
||||
Plus,
|
||||
@@ -48,7 +47,6 @@ import {
|
||||
isBrowserViewportOccluded
|
||||
} from './browser-viewport-occlusion'
|
||||
import {
|
||||
findTaskSchedule,
|
||||
TaskScheduleActions
|
||||
} from './TaskScheduleActions'
|
||||
import type {
|
||||
@@ -883,8 +881,7 @@ export function RightAssistantSidebar({
|
||||
useState('')
|
||||
const [taskFilter, setTaskFilter] = useState<
|
||||
'all' | 'active' | 'paused' | 'finished'
|
||||
>('all')
|
||||
const [taskFiltersExpanded, setTaskFiltersExpanded] = useState(false)
|
||||
>('active')
|
||||
const [taskListExpanded, setTaskListExpanded] = useState(false)
|
||||
const [actionErrorState, setActionErrorState] = useState({
|
||||
scope: { instanceId: activeWorkbarInstanceId, open },
|
||||
@@ -1027,6 +1024,14 @@ export function RightAssistantSidebar({
|
||||
}),
|
||||
[approvalsByTask, taskFilter, topLevelTasks]
|
||||
)
|
||||
const schedulesByTaskKey = useMemo(() => {
|
||||
const byKey = new Map<string, AssistantSchedule>()
|
||||
for (const schedule of schedules) {
|
||||
byKey.set(schedule.id, schedule)
|
||||
byKey.set(schedule.taskId, schedule)
|
||||
}
|
||||
return byKey
|
||||
}, [schedules])
|
||||
|
||||
useEffect(() => {
|
||||
// Context switches preserve the selected instance and its pinned binding.
|
||||
@@ -1981,21 +1986,8 @@ export function RightAssistantSidebar({
|
||||
>
|
||||
<Plus aria-hidden="true" size={13} />
|
||||
</button>
|
||||
<button
|
||||
className="secondary-button task-center__filter-toggle"
|
||||
aria-label={t('sidebar.tasks.filters.ariaLabel')}
|
||||
title={t('sidebar.tasks.filters.ariaLabel')}
|
||||
aria-expanded={taskListExpanded && taskFiltersExpanded}
|
||||
aria-controls={`task-filters-${instance.id}`}
|
||||
data-active={taskFilter !== 'all'}
|
||||
onClick={() => {
|
||||
setTaskListExpanded(true)
|
||||
setTaskFiltersExpanded((expanded) => !expanded)
|
||||
}}
|
||||
type="button"
|
||||
><Filter aria-hidden="true" size={14} /></button>
|
||||
</div>
|
||||
<div className="task-center__filters" id={`task-filters-${instance.id}`} hidden={!taskListExpanded || !taskFiltersExpanded}
|
||||
<div className="task-center__filters" id={`task-filters-${instance.id}`} hidden={!taskListExpanded}
|
||||
onFocusCapture={(event) => event.target.scrollIntoView?.({ block: 'nearest', inline: 'nearest' })}>
|
||||
<SegmentedControl
|
||||
ariaLabel={t('sidebar.tasks.filters.ariaLabel')}
|
||||
@@ -2018,10 +2010,6 @@ export function RightAssistantSidebar({
|
||||
value={taskFilter}
|
||||
/>
|
||||
</div>
|
||||
{taskListExpanded && taskFilter !== 'all' && <div className="task-center__filter-summary">
|
||||
<span>{t('sidebar.tasks.filters.summary', { filter: t(`sidebar.tasks.filters.${taskFilter}`), count: filteredTasks.length })}</span>
|
||||
<button type="button" onClick={() => setTaskFilter('all')}>{t('sidebar.tasks.filters.clear')}</button>
|
||||
</div>}
|
||||
{unassociatedApprovals.length > 0 && <>
|
||||
<h3><ShieldAlert size={15} />{t('sidebar.tasks.approvalsTitle')}</h3>
|
||||
{unassociatedApprovals.map((approval) => (
|
||||
@@ -2037,7 +2025,9 @@ export function RightAssistantSidebar({
|
||||
</p>
|
||||
) : (
|
||||
filteredTasks.map((task) => {
|
||||
const schedule = findTaskSchedule(task, schedules)
|
||||
const schedule =
|
||||
schedulesByTaskKey.get(task.scheduleId ?? '') ??
|
||||
schedulesByTaskKey.get(task.id)
|
||||
const conversationTitle = task.conversationId
|
||||
? conversationTitles.get(task.conversationId)
|
||||
: undefined
|
||||
|
||||
@@ -81,8 +81,13 @@
|
||||
.task-center__list { display: flex; flex-direction: column; gap: var(--space-2); }
|
||||
.task-center__list[hidden] { display: none; }
|
||||
|
||||
.task-center .task-center__create,
|
||||
.task-center .task-center__filter-toggle {
|
||||
/* Keep expanding a long history responsive by skipping off-screen cards. */
|
||||
.task-center__list > .task-center__item {
|
||||
content-visibility: auto;
|
||||
contain-intrinsic-size: 0 132px;
|
||||
}
|
||||
|
||||
.task-center .task-center__create {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -92,13 +97,6 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.task-center .task-center__filter-toggle[data-active='true'],
|
||||
.task-center .task-center__filter-toggle[aria-expanded='true'] {
|
||||
border-color: var(--accent-selected);
|
||||
background: var(--accent-subtle);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.task-center .task-center__filters { flex: 0 0 auto; }
|
||||
.task-center .task-center__filters .segmented-control { overflow-x: auto; }
|
||||
.task-center .task-center__filters .segmented-control__option {
|
||||
@@ -107,26 +105,6 @@
|
||||
}
|
||||
.task-center .task-center__filters[hidden] { display: none; }
|
||||
|
||||
.task-center__filter-summary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-2);
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-caption);
|
||||
}
|
||||
|
||||
.task-center__filter-summary button {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--accent);
|
||||
padding: var(--space-2);
|
||||
cursor: pointer;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.task-center__filter-summary button:hover { background: var(--accent-subtle); }
|
||||
.task-center button:focus-visible,
|
||||
.task-center summary:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
|
||||
Reference in New Issue
Block a user