feat: 在顶栏并排展示下发智能体并直接切换
This commit is contained in:
@@ -13,7 +13,14 @@ export function Layout() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [width, setWidth] = useState(508);
|
||||
const [long, setLong] = useState(true);
|
||||
const count = Number(new URLSearchParams(location.search).get('agents') ?? 0);
|
||||
const [selected, setSelected] = useState(0);
|
||||
const agents = Array.from({ length: count }, (_, index) => ({
|
||||
teacher_id: `agent-${index}`, version: index + 1, is_default: index === 0,
|
||||
definition: { config_id: `agent-${index}`, name: `智能体${index + 1}`, avatar_id: 'avatar-06' },
|
||||
}));
|
||||
const companion = {
|
||||
agents, selectedAgent: agents[selected],
|
||||
definition: { name: '编程老师', avatar_id: 'avatar-06' },
|
||||
invitation: visible ? { response: long ? '你刚才说想做一个宠物游戏。我们一起想想,什么样的小动作,会让你愿意一直陪它玩下去?可以先挑一个最想试的想法。' : '有什么编程问题想一起讨论?' } : null,
|
||||
welcome: null, enabled: true, loading: false, checking: false, error: null,
|
||||
@@ -21,9 +28,9 @@ export function Layout() {
|
||||
} as ComponentProps<typeof TeacherCompanion>['companion'];
|
||||
return <div className="classroom-workspace flex h-screen flex-col bg-white">
|
||||
<header className="relative z-50 flex h-10 shrink-0 items-center justify-end border-b px-3" data-testid="coding-conversation-header">
|
||||
<span className="mr-auto text-xs">布局测试项目 › hello</span>
|
||||
<TeacherCompanion companion={companion} open={open} onOpen={() => setOpen(!open)} bubbleRef={setBubble} />
|
||||
<span className="w-20 text-center text-xs">朋友</span>
|
||||
<span className="mr-auto min-w-0 truncate text-xs">布局测试项目 › hello</span>
|
||||
<TeacherCompanion companion={companion} open={open} onOpen={(id) => { if (id) setSelected(agents.findIndex((item) => item.teacher_id === id)); setOpen(!open); }} bubbleRef={setBubble} />
|
||||
<span data-testid="window-controls" className="w-[132px] shrink-0 text-center text-xs">— □ ×</span>
|
||||
</header>
|
||||
<div className="relative flex min-h-0 flex-1" data-testid="coding-chat-panel" data-consultation-open={open}>
|
||||
<main className="flex min-w-0 flex-1 flex-col">
|
||||
|
||||
@@ -539,7 +539,7 @@ async function installCodingFirstChatHost(
|
||||
const topicBase = `/${consultationPath}-topics`;
|
||||
const topicId = `${consultationPath}-topic`;
|
||||
const currentTopic = consultationTopics[consultationPath];
|
||||
if (path.endsWith(topicBase) && method === 'GET') return respond({items:currentTopic?[{id:currentTopic.id,title:'智能体话题'}]:[],lastSelectedTopicId:currentTopic?.id??null});
|
||||
if (path.endsWith(topicBase) && method === 'GET') return respond({items:currentTopic?[{id:currentTopic.id,title:'智能体话题',teacherId:(currentTopic.definition as {config_id?:string}).config_id}]:[],lastSelectedTopicId:currentTopic?.id??null});
|
||||
if (path.endsWith(topicBase) && method === 'POST') {
|
||||
const selected = teachers.find(item => item.version === body?.teacherVersion) ?? teachers[0];
|
||||
consultationTopics[consultationPath]={schemaVersion:1,revision:0,id:topicId,accountId:'e2e',projectId:project.id,sourceConversationId:conversation.id,definition:selected.definition,version:selected.version,createdAt:now,updatedAt:now,requests:[]};
|
||||
@@ -1778,14 +1778,16 @@ test('project consultations preserve student drafts and switch between work and
|
||||
await expect(composer).toBeHidden();
|
||||
await page.getByRole('tab',{name:'操作对话',exact:true}).click();
|
||||
await expect(composer).toHaveValue('保留我的草稿');
|
||||
await page.getByRole('button',{name:'智能体',exact:true}).click();
|
||||
await page.getByRole('button',{name:'与朋友聊天',exact:true}).click();
|
||||
const teacher=page.getByTestId('teacher-chat-panel');
|
||||
await expect(page.getByRole('tab',{name:'作品',exact:true})).toHaveAttribute('aria-selected','true');
|
||||
await expect(page.getByRole('tabpanel',{name:'作品',exact:true})).toBeVisible();
|
||||
await expect(composer).toBeHidden();
|
||||
await expect(composer).toHaveValue('保留我的草稿');
|
||||
await expect(teacher.getByText('一起理解代码')).toBeVisible();
|
||||
await teacher.getByRole('combobox', { name: '新话题使用的智能体' }).selectOption('9');
|
||||
await expect(teacher.getByRole('combobox', { name: '新话题使用的智能体' })).toHaveCount(0);
|
||||
await expect(page.getByRole('button', { name: '与代码智能体聊天' })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: '与朋友聊天' })).toHaveAttribute('aria-pressed', 'true');
|
||||
await expect(page.locator('#coding-consultation-dock')).toHaveCSS('width', '508px');
|
||||
await expect(teacher.getByTestId('consultation-composer-actions').getByRole('button', { name: '帮我看看', exact: true })).toBeVisible();
|
||||
await expect(teacher.getByText('把你的困惑说出来就好')).toHaveCount(0);
|
||||
@@ -1810,8 +1812,11 @@ test('project consultations preserve student drafts and switch between work and
|
||||
await page.getByRole('tab',{name:'操作对话',exact:true}).click();
|
||||
await expect(composer).toBeVisible();
|
||||
await teacher.getByRole('button',{name:'关闭智能体'}).click();
|
||||
await expect(page.getByRole('button',{name:'朋友',exact:true})).toHaveCount(0);
|
||||
await page.getByRole('button',{name:'智能体',exact:true}).click();
|
||||
await page.getByRole('button', { name: '与代码智能体聊天' }).click();
|
||||
await expect(teacher.getByRole('heading', { name: '代码智能体' })).toBeVisible();
|
||||
await expect(teacher.getByRole('textbox', { name: '向智能体提问' })).toHaveValue('');
|
||||
await teacher.getByRole('textbox', { name: '向智能体提问' }).fill('另一个智能体的草稿');
|
||||
await page.getByRole('button',{name:'与朋友聊天',exact:true}).click();
|
||||
await expect(teacher.getByRole('textbox',{name:'向智能体提问'})).toHaveValue('还没说完的困惑');
|
||||
await expect(teacher.getByText('先理解状态如何随点击变化,再修改代码。')).toBeVisible();
|
||||
const requests=(await readState(electronApp)).captured;
|
||||
@@ -1826,7 +1831,7 @@ test('project consultations preserve student drafts and switch between work and
|
||||
expect(consultationRequests[2].body).toMatchObject({intent:'guided-help',text:'我也说不清,你带我看看'});
|
||||
await page.screenshot({path:test.info().outputPath('project-teacher-side-chat.png')});
|
||||
await teacher.getByRole('button',{name:'关闭智能体'}).click();await expect(teacher).toHaveCount(0);
|
||||
await page.getByRole('button',{name:'智能体',exact:true}).click();
|
||||
await page.getByRole('button',{name:'与朋友聊天',exact:true}).click();
|
||||
await expect(page.getByText('先理解状态如何随点击变化,再修改代码。',{exact:true})).toBeVisible();
|
||||
await expect(teacher.getByRole('textbox',{name:'向智能体提问'})).toHaveValue('还没说完的困惑');
|
||||
} finally {await releaseSnapshot(electronApp);}
|
||||
|
||||
@@ -23,7 +23,7 @@ test.beforeAll(async () => {
|
||||
},
|
||||
configureServer(vite) {
|
||||
vite.middlewares.use((req, res, next) => {
|
||||
if (req.url !== '/') return next();
|
||||
if (req.url !== '/' && !req.url?.startsWith('/?')) return next();
|
||||
res.setHeader('Content-Type', 'text/html');
|
||||
res.end('<html><head><meta charset="utf-8"></head><body><div id="root"></div><script type="module" src="/tests/e2e/fixtures/teacher-preview-layout.tsx"></script></body></html>');
|
||||
});
|
||||
@@ -35,6 +35,30 @@ test.beforeAll(async () => {
|
||||
});
|
||||
test.afterAll(async () => { await server?.close(); });
|
||||
|
||||
for (const width of [520, 1000]) {
|
||||
test(`distributed agent tabs scroll inside the title bar at ${width}px`, async ({ page }) => {
|
||||
await page.setViewportSize({ width, height: 800 });
|
||||
await page.goto(baseUrl + '?agents=8');
|
||||
const tabs = page.getByRole('navigation', { name: '已下发智能体' });
|
||||
await expect(tabs.getByRole('button')).toHaveCount(8);
|
||||
await expect(page.getByRole('combobox', { name: '新话题使用的智能体' })).toHaveCount(0);
|
||||
const last = tabs.getByRole('button', { name: '与智能体8聊天' });
|
||||
await last.focus();
|
||||
await last.press('Enter');
|
||||
await expect(last).toHaveAttribute('aria-pressed', 'true');
|
||||
const bounds = await page.evaluate(() => {
|
||||
const strip = document.querySelector('.consultation-agent-tabs')!;
|
||||
const controls = document.querySelector('[data-testid="window-controls"]')!;
|
||||
return { right: strip.getBoundingClientRect().right, controlsLeft: controls.getBoundingClientRect().left,
|
||||
scroll: strip.scrollLeft, documentWidth: document.documentElement.scrollWidth };
|
||||
});
|
||||
expect(bounds.right).toBeLessThanOrEqual(bounds.controlsLeft);
|
||||
expect(bounds.documentWidth).toBeLessThanOrEqual(width);
|
||||
expect(bounds.scroll).toBeGreaterThan(0);
|
||||
await page.screenshot({ path: test.info().outputPath('distributed-agents-titlebar.png') });
|
||||
});
|
||||
}
|
||||
|
||||
async function geometry(page: Page) {
|
||||
return page.evaluate(() => {
|
||||
const box = (selector: string) => document.querySelector(selector)!.getBoundingClientRect();
|
||||
|
||||
Reference in New Issue
Block a user