feat(web): indicate session activity in date picker (#1103)

* feat(web): indicate session activity in date picker

* fix(web): expose session activity to assistive tech
This commit is contained in:
Ananovo
2026-07-24 10:56:20 +08:00
committed by GitHub
parent 735ccda168
commit 0834dc098c
4 changed files with 27 additions and 5 deletions
@@ -143,8 +143,13 @@ describe('SessionList time filter', () => {
expect(screen.getByRole('button', { name: /Old session/ })).toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: 'Filter sessions by last activity' }))
fireEvent.click(screen.getByRole('button', { name: new Date(2026, 6, 17).toLocaleDateString() }))
fireEvent.click(screen.getByRole('button', { name: new Date(2026, 6, 18).toLocaleDateString() }))
const emptyDate = screen.getByRole('button', { name: new Date(2026, 6, 17).toLocaleDateString() })
const activeDate = screen.getByRole('button', { name: `${new Date(2026, 6, 18).toLocaleDateString()}, has session activity` })
expect(emptyDate).toHaveClass('text-[var(--app-hint)]')
expect(activeDate).toHaveClass('text-[var(--app-fg)]')
expect(activeDate).toHaveAttribute('title', `${new Date(2026, 6, 18).toLocaleDateString()}, has session activity`)
fireEvent.click(emptyDate)
fireEvent.click(activeDate)
expect(screen.getByRole('button', { name: /Recent session/ })).toBeInTheDocument()
expect(screen.queryByRole('button', { name: /Old session/ })).toBeNull()
@@ -174,7 +179,7 @@ describe('SessionList time filter', () => {
fireEvent.click(filterButton)
fireEvent.click(screen.getByRole('button', { name: new Date(2026, 6, 1).toLocaleDateString() }))
expect(screen.getByText('Select end date')).toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: new Date(2026, 6, 18).toLocaleDateString() }))
fireEvent.click(screen.getByRole('button', { name: `${new Date(2026, 6, 18).toLocaleDateString()}, has session activity` }))
expect(filterButton).toHaveAttribute('aria-expanded', 'false')
expect(filterButton).toHaveAttribute('title', '2026-07-01 2026-07-18')
+17 -2
View File
@@ -573,6 +573,7 @@ function formatDateValue(date: Date): string {
function SessionDateRangePicker(props: {
start: string
end: string
sessionActivityDates: ReadonlySet<string>
onChange: (start: string, end: string) => void
onClose: () => void
}) {
@@ -627,17 +628,24 @@ function SessionDateRangePicker(props: {
const value = formatDateValue(date)
const isEndpoint = value === props.start || value === props.end
const isInRange = Boolean(props.start && props.end && value > props.start && value < props.end)
const hasSessionActivity = props.sessionActivityDates.has(value)
const dateLabel = date.toLocaleDateString()
const activityLabel = hasSessionActivity
? t('sessions.timeFilter.dayWithActivity', { date: dateLabel })
: dateLabel
return (
<button
key={value}
type="button"
onClick={() => selectDate(value)}
aria-label={date.toLocaleDateString()}
aria-label={activityLabel}
title={hasSessionActivity ? activityLabel : undefined}
className={cn(
'h-8 rounded-lg text-xs transition-colors',
isEndpoint && 'bg-[var(--app-link)] text-white',
isInRange && 'bg-[var(--app-link)]/15 text-[var(--app-link)]',
!isEndpoint && !isInRange && 'hover:bg-[var(--app-subtle-bg)]'
!isEndpoint && !isInRange && hasSessionActivity && 'text-[var(--app-fg)] hover:bg-[var(--app-subtle-bg)]',
!isEndpoint && !isInRange && !hasSessionActivity && 'text-[var(--app-hint)] hover:bg-[var(--app-subtle-bg)]'
)}
>
{index + 1}
@@ -668,6 +676,7 @@ function SessionListSearch(props: {
onChange: (value: string) => void
customStart: string
customEnd: string
sessionActivityDates: ReadonlySet<string>
onDateRangeChange: (start: string, end: string) => void
}) {
const { t } = useTranslation()
@@ -719,6 +728,7 @@ function SessionListSearch(props: {
<SessionDateRangePicker
start={props.customStart}
end={props.customEnd}
sessionActivityDates={props.sessionActivityDates}
onChange={props.onDateRangeChange}
onClose={() => setDatePickerOpen(false)}
/>
@@ -1051,6 +1061,10 @@ export function SessionList(props: {
},
[props.sessions, selectedSessionId, showActiveSessionsOnly]
)
const sessionActivityDates = useMemo(
() => new Set(allSessions.map(session => formatDateValue(new Date(session.updatedAt)))),
[allSessions]
)
const visibleSessions = useMemo(
() => isFiltering
? allSessions.filter(session => (
@@ -1246,6 +1260,7 @@ export function SessionList(props: {
onChange={setSearchQuery}
customStart={customStart}
customEnd={customEnd}
sessionActivityDates={sessionActivityDates}
onDateRangeChange={(start, end) => {
setCustomStart(start)
setCustomEnd(end)
+1
View File
@@ -60,6 +60,7 @@ export default {
'sessions.timeFilter.close': 'Close date picker',
'sessions.timeFilter.previousMonth': 'Previous month',
'sessions.timeFilter.nextMonth': 'Next month',
'sessions.timeFilter.dayWithActivity': '{date}, has session activity',
'sessions.group.showMore': 'Show {n} more',
'sessions.group.showLess': 'Show less',
'sessions.group.new': 'New session in this directory',
+1
View File
@@ -60,6 +60,7 @@ export default {
'sessions.timeFilter.close': '关闭日期选择器',
'sessions.timeFilter.previousMonth': '上个月',
'sessions.timeFilter.nextMonth': '下个月',
'sessions.timeFilter.dayWithActivity': '{date},有会话活动',
'sessions.group.showMore': '再显示 {n} 个',
'sessions.group.showLess': '收起',
'sessions.group.new': '在此目录新建会话',