✨ feat(vscode): 问 AI 输入框旁边能选 Claude profile,记住上次选的,问答灰字写用哪个 profile 答的

This commit is contained in:
cruldra committed 2026-09-26 22:28:29 +08:00
1 parent 1eb42d8389
commit 9efae1f496
20 files changed
+397 -63

No files matched your search

@@ -1,6 +1,6 @@
import type { AskThreadProps } from './AskThread'
import type { Ask } from './qa'
import type { QaEntryView } from './types'
import type { ProfileChoice, QaEntryView } from './types'
import { renderToStaticMarkup } from 'react-dom/server'
import { describe, expect, it } from 'vitest'
import { AskThread } from './AskThread'
@@ -12,8 +12,10 @@ const HISTORY: QaEntryView[] = [
{ id: 'e2', question: 'UserRole 还有哪些角色?', answer: '只有 ADMIN 和 USER。', createdAt: new Date(2026, 8, 25, 10, 0).toISOString() },
]
const PROFILES: ProfileChoice = { options: [{ id: 'offical', label: 'offical' }, { id: 'sonnet', label: 'sonnet' }], selected: 'sonnet' }
function render(props: Partial<AskThreadProps>): string {
return renderToStaticMarkup(<AskThread history={[]} asks={[]} open={false} now={NOW} onAsk={() => {}} onStop={() => {}} onDelete={() => {}} onClose={() => {}} {...props} />)
return renderToStaticMarkup(<AskThread history={[]} asks={[]} open={false} profiles={PROFILES} now={NOW} onSelectProfile={() => {}} onAsk={() => {}} onStop={() => {}} onDelete={() => {}} onClose={() => {}} {...props} />)
}
const text = (html: string): string => html.replace(/<[^>]*>/g, '')
@@ -67,4 +69,27 @@ describe('块下面的问答区', () => {
expect(text(render({ open: true, asks: [ask({ status: 'stopped', text: '一半' })] }))).toContain('已停止,这次没存。')
expect(text(render({ open: true, asks: [ask({})] }))).toContain('正在想…')
})
it('输入框右边、发送按钮前面是 profile 下拉:显示选中的名字,键盘能打开(按钮、弹出列表);没收到选项时写「默认」', () => {
const html = render({ open: true })
const row = html.slice(html.indexOf('<div class="cr-qa-input">'))
const [textarea, select, send] = ['<textarea', 'cr-qa-profile', 'aria-label="发送"'].map(mark => row.indexOf(mark))
expect(textarea).toBeGreaterThanOrEqual(0)
expect(select).toBeGreaterThan(textarea)
expect(send).toBeGreaterThan(select)
const trigger = row.slice(row.lastIndexOf('<button', select), row.indexOf('</button>', select))
expect(trigger).toContain('aria-haspopup="listbox"')
expect(trigger).toContain('aria-expanded="false"')
expect(trigger).toContain('title="用哪个 Claude Code 配置(profile)回答,下一个问题起用它"')
expect(text(trigger)).toBe('sonnet')
const none = render({ open: true, profiles: { options: [], selected: '' } })
expect(text(none.slice(none.indexOf('cr-qa-profile')))).toContain('默认')
})
it('历史每条的灰字写时间和用哪个 profile 答的;以前存的没有 profile 只写时间', () => {
const html = render({ open: true, history: [{ ...HISTORY[0]!, profile: 'sonnet' }, HISTORY[1]!] })
expect(text(html)).toContain('为什么普通用户不能看别人的资料?3 天前 · sonnet')
expect(text(html)).toContain('UserRole 还有哪些角色?昨天')
expect(text(html)).not.toContain('昨天 ·')
})
})