Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -98,60 +98,22 @@ async function render(props: Partial<Parameters<typeof ChatsSection>[0]> = {}) {
}

describe('ChatsSection', () => {
it('shows five chats with the workspace-style See more and See less controls', async () => {
it('shows all chats without pagination controls', async () => {
await render()
expect(container.querySelectorAll('a[href^="/o/org-1/chat/"]')).toHaveLength(5)
const more = Array.from(container.querySelectorAll('button')).find(
(button) => button.textContent === 'See more'
)!
await act(async () => more.click())
expect(container.querySelectorAll('a[href^="/o/org-1/chat/"]')).toHaveLength(8)
const less = Array.from(container.querySelectorAll('button')).find(
(button) => button.textContent === 'See less'
)!
await act(async () => less.click())
expect(container.querySelectorAll('a[href^="/o/org-1/chat/"]')).toHaveLength(5)
expect(container.textContent).not.toContain('See more')
expect(container.textContent).not.toContain('See less')
})

it('marks the chat on the current route active', async () => {
await render({ pathname: '/o/org-1/chat/chat-3' })
await render({ pathname: '/o/org-1/chat/chat-8' })

const current = container.querySelector('a[href="/o/org-1/chat/chat-3"]')
const current = container.querySelector('a[href="/o/org-1/chat/chat-8"]')
const other = container.querySelector('a[href="/o/org-1/chat/chat-4"]')
expect(current?.className).toContain('surface-active')
expect(other?.className).not.toContain('surface-active')
})

it('keeps a bookmarked chat visible when collapsing expanded history', async () => {
await render({ pathname: CHATS[5].href })
expect(container.querySelectorAll('a[href^="/o/org-1/chat/"]')).toHaveLength(6)
expect(container.querySelector(`a[href="${CHATS[5].href}"]`)?.className).toContain(
'surface-active'
)
const more = Array.from(container.querySelectorAll('button')).find(
(button) => button.textContent === 'See more'
)!
await act(async () => more.click())
expect(container.querySelectorAll('a[href^="/o/org-1/chat/"]')).toHaveLength(8)
const less = Array.from(container.querySelectorAll('button')).find(
(button) => button.textContent === 'See less'
)!
await act(async () => less.click())
expect(container.querySelectorAll('a[href^="/o/org-1/chat/"]')).toHaveLength(6)
expect(container.querySelector(`a[href="${CHATS[5].href}"]`)).not.toBeNull()
})

it('derives the visible range from the route without retaining automatic expansion', async () => {
await render({ pathname: CHATS[7].href })
expect(container.querySelectorAll('a[href^="/o/org-1/chat/"]')).toHaveLength(8)
expect(container.textContent).not.toContain('See more')
expect(container.textContent).not.toContain('See less')

await render({ pathname: null })
expect(container.querySelectorAll('a[href^="/o/org-1/chat/"]')).toHaveLength(5)
expect(container.textContent).toContain('See more')
})

it.each([false, true])('renames via the options menu with collapsed=%s', async (isCollapsed) => {
hoverState.isOpen = isCollapsed
await render({ isCollapsed })
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
'use client'

import { useState } from 'react'
import {
Chip,
ChipInput,
chipVariants,
cn,
Expand Down Expand Up @@ -117,8 +115,6 @@ interface ChatsSectionProps {
pathname: string | null
}

const PAGE_SIZE = 5

export function ChatsSection({
organizationId,
chats,
Expand All @@ -128,10 +124,6 @@ export function ChatsSection({
}: ChatsSectionProps) {
const actions = useOrganizationChatActions({ organizationId, chats })
const { menu, hover, rename, selectedChat } = actions
const [requestedCount, setRequestedCount] = useState(PAGE_SIZE)
const minimumCount = Math.max(PAGE_SIZE, chats.findIndex((chat) => chat.href === pathname) + 1)
const visibleCount = Math.min(chats.length, Math.max(requestedCount, minimumCount))
const hasMore = chats.length > visibleCount
const menuOpenChatId = menu.isOpen ? selectedChat?.id : null
const saveRename = () => {
void rename.saveRename()
Expand Down Expand Up @@ -192,43 +184,31 @@ export function ChatsSection({
No chats yet
</div>
)}
{chats
.slice(0, visibleCount)
.map((chat) =>
rename.editingId === chat.id ? (
<ChipInput
key={chat.id}
ref={rename.inputRef}
aria-label={`Rename chat ${chat.name}`}
value={rename.value}
onChange={(event) => rename.setValue(event.target.value)}
onKeyDown={rename.handleKeyDown}
onBlur={saveRename}
disabled={rename.isSaving}
maxLength={100}
autoComplete='off'
/>
) : (
<ChatRow
key={chat.id}
chat={chat}
isCurrentRoute={pathname === chat.href}
isMenuOpen={menuOpenChatId === chat.id}
onContextMenu={actions.onContextMenu}
onMorePointerDown={actions.onMorePointerDown}
onMoreClick={actions.onMoreClick}
/>
)
)}
{(hasMore || visibleCount > minimumCount) && (
<Chip
fullWidth
onClick={() =>
setRequestedCount(hasMore ? visibleCount + PAGE_SIZE : PAGE_SIZE)
}
>
{hasMore ? 'See more' : 'See less'}
</Chip>
{chats.map((chat) =>
rename.editingId === chat.id ? (
<ChipInput
key={chat.id}
ref={rename.inputRef}
aria-label={`Rename chat ${chat.name}`}
value={rename.value}
onChange={(event) => rename.setValue(event.target.value)}
onKeyDown={rename.handleKeyDown}
onBlur={saveRename}
disabled={rename.isSaving}
maxLength={100}
autoComplete='off'
/>
) : (
<ChatRow
key={chat.id}
chat={chat}
isCurrentRoute={pathname === chat.href}
isMenuOpen={menuOpenChatId === chat.id}
onContextMenu={actions.onContextMenu}
onMorePointerDown={actions.onMorePointerDown}
onMoreClick={actions.onMoreClick}
/>
)
)}
</>
)}
Expand Down
Loading