mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
Always reveal newly sent chat prompts
Sending from history must move the transcript to the new turn even if session state has not yet advanced from idle. The previous guard tied the jump to chatState, so a user_text tail that landed before thinking/streaming would be skipped permanently because the tail id no longer changed. Constraint: The same MessageList path serves desktop and H5 chat. Rejected: Wait for chatState to become thinking before scrolling | that misses updates where the message id is already recorded. Confidence: high Scope-risk: narrow Directive: New user_text tail messages are intentional navigation events and must override historical scroll position. Tested: cd desktop && bun run test -- MessageList.test.tsx Tested: cd desktop && bun run lint Tested: cd desktop && bun run build Tested: git diff --check
This commit is contained in:
parent
76d472376b
commit
5871af11d4
@ -1342,6 +1342,98 @@ describe('MessageList nested tool calls', () => {
|
||||
expect(screen.queryByRole('button', { name: 'Latest' })).toBeNull()
|
||||
})
|
||||
|
||||
it('jumps to the latest message when a sent prompt lands before chat state changes', async () => {
|
||||
const scrollIntoView = vi.fn()
|
||||
Object.defineProperty(HTMLElement.prototype, 'scrollIntoView', {
|
||||
configurable: true,
|
||||
value: scrollIntoView,
|
||||
})
|
||||
|
||||
useChatStore.setState({
|
||||
sessions: {
|
||||
[ACTIVE_TAB]: makeSessionState({
|
||||
messages: [
|
||||
{
|
||||
id: 'user-1',
|
||||
type: 'user_text',
|
||||
content: '历史消息',
|
||||
timestamp: 1,
|
||||
},
|
||||
{
|
||||
id: 'assistant-1',
|
||||
type: 'assistant_text',
|
||||
content: '历史回复',
|
||||
timestamp: 2,
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
const { container } = render(<MessageList />)
|
||||
const scroller = container.querySelector('.overflow-y-auto') as HTMLDivElement
|
||||
let scrollTop = 120
|
||||
Object.defineProperty(scroller, 'scrollHeight', { configurable: true, value: 1000 })
|
||||
Object.defineProperty(scroller, 'clientHeight', { configurable: true, value: 400 })
|
||||
Object.defineProperty(scroller, 'scrollTop', {
|
||||
configurable: true,
|
||||
get: () => scrollTop,
|
||||
set: (value) => {
|
||||
scrollTop = value
|
||||
},
|
||||
})
|
||||
|
||||
scrollIntoView.mockClear()
|
||||
await waitForProgrammaticScrollReset()
|
||||
fireEvent.scroll(scroller)
|
||||
expect(screen.getByRole('button', { name: 'Latest' })).toBeTruthy()
|
||||
|
||||
act(() => {
|
||||
useChatStore.setState((state) => ({
|
||||
sessions: {
|
||||
...state.sessions,
|
||||
[ACTIVE_TAB]: {
|
||||
...state.sessions[ACTIVE_TAB]!,
|
||||
chatState: 'idle',
|
||||
messages: [
|
||||
...state.sessions[ACTIVE_TAB]!.messages,
|
||||
{
|
||||
id: 'user-2',
|
||||
type: 'user_text',
|
||||
content: '刚发送的问题',
|
||||
timestamp: 3,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('刚发送的问题')).toBeTruthy()
|
||||
})
|
||||
expect(scrollIntoView).not.toHaveBeenCalled()
|
||||
expect(scrollTop).toBe(600)
|
||||
expect(screen.queryByRole('button', { name: 'Latest' })).toBeNull()
|
||||
|
||||
act(() => {
|
||||
useChatStore.setState((state) => ({
|
||||
sessions: {
|
||||
...state.sessions,
|
||||
[ACTIVE_TAB]: {
|
||||
...state.sessions[ACTIVE_TAB]!,
|
||||
chatState: 'thinking',
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('刚发送的问题')).toBeTruthy()
|
||||
})
|
||||
expect(scrollTop).toBe(600)
|
||||
})
|
||||
|
||||
it('keeps user actions anchored to the right bubble and assistant actions to the left bubble', () => {
|
||||
useChatStore.setState({
|
||||
sessions: {
|
||||
|
||||
@ -646,10 +646,10 @@ export function MessageList({ sessionId, compact = false }: MessageListProps = {
|
||||
lastTailMessageIdBySessionRef.current.set(resolvedSessionId, tailMessageId)
|
||||
if (previousTailMessageId === undefined || previousTailMessageId === tailMessageId) return
|
||||
|
||||
if (tailMessageType === 'user_text' && chatState !== 'idle') {
|
||||
if (tailMessageType === 'user_text') {
|
||||
scrollToBottom('auto')
|
||||
}
|
||||
}, [chatState, resolvedSessionId, scrollToBottom, tailMessageId, tailMessageType])
|
||||
}, [resolvedSessionId, scrollToBottom, tailMessageId, tailMessageType])
|
||||
|
||||
useEffect(() => {
|
||||
if (!shouldAutoScrollRef.current) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user