feat(coding): add conversation archive and first-message titles
This commit is contained in:
@@ -109,6 +109,7 @@ async function installCodingFirstChatHost(
|
||||
};
|
||||
mainGlobal.__makelorePiFirstChatE2E = state;
|
||||
const now = '2026-08-24T00:00:00.000Z';
|
||||
const metadata = new Map<string, Record<string, unknown>>();
|
||||
const project = {
|
||||
id: 'project-pi-first-chat',
|
||||
name: 'PI first chat',
|
||||
@@ -545,11 +546,11 @@ async function installCodingFirstChatHost(
|
||||
}
|
||||
if (path === `/api/coding/projects/conversations?projectId=${project.id}`) {
|
||||
return respond({
|
||||
conversations: featureComplete
|
||||
conversations: (featureComplete
|
||||
? [conversation, secondConversation, historyConversation]
|
||||
: state.conversationCreated
|
||||
? [conversation]
|
||||
: [],
|
||||
: []).map((item) => ({ ...item, ...metadata.get(item.id) })),
|
||||
});
|
||||
}
|
||||
if (path.startsWith('/api/agent-browser/state?')) {
|
||||
@@ -712,7 +713,14 @@ async function installCodingFirstChatHost(
|
||||
return respond({ conversation: { ...conversation, id: 'conversation-forked', title: 'Feature UI branch' } }, 201);
|
||||
}
|
||||
if (/^\/api\/coding\/conversations\/[^/]+$/.test(path) && method === 'PATCH') {
|
||||
return respond({ conversation: { ...conversation, ...(body?.title ? { title: body.title } : {}), unread: body?.unread === true, archivedAt: body?.archived === true ? now : null } });
|
||||
const target = [conversation, secondConversation, historyConversation].find((item) => path.endsWith('/' + item.id)) ?? conversation;
|
||||
const updated = { ...target, ...metadata.get(target.id),
|
||||
...(body?.title ? { title: body.title } : {}),
|
||||
...(typeof body?.unread === 'boolean' ? { unread: body.unread } : {}),
|
||||
...(typeof body?.archived === 'boolean' ? { archivedAt: body.archived ? now : null } : {}),
|
||||
};
|
||||
metadata.set(target.id, updated);
|
||||
return respond({ conversation: updated });
|
||||
}
|
||||
if (/^\/api\/coding\/interactions\/[^/]+\/respond$/.test(path) && method === 'POST') {
|
||||
state.interactionAnswered = true;
|
||||
@@ -770,6 +778,54 @@ async function settleSnapshot(electronApp: ElectronApplication): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
test('conversation menus rename, archive and restore without selecting or stopping the target', async ({ launchElectronApp }) => {
|
||||
const electronApp = await launchElectronApp({ skipSetup: true });
|
||||
let page = await getStableWindow(electronApp);
|
||||
const connection = await page.evaluate(async () => ({
|
||||
token: await window.electron.ipcRenderer.invoke('hostapi:token') as string,
|
||||
baseUrl: await window.electron.ipcRenderer.invoke('hostapi:base-url') as string,
|
||||
}));
|
||||
await installCodingFirstChatHost(electronApp, connection, true);
|
||||
await settleSnapshot(electronApp);
|
||||
await disableCodingEventSource(page);
|
||||
try {
|
||||
await page.reload();
|
||||
page = await getStableWindow(electronApp);
|
||||
await page.getByTestId('ai-module-option-programming').click();
|
||||
await page.evaluate(() => { window.location.hash = '/chat'; });
|
||||
const sidebar = page.getByTestId('coding-conversation-sidebar');
|
||||
const header = page.getByTestId('coding-conversation-header');
|
||||
await expect(header).toContainText('新对话');
|
||||
await sidebar.getByRole('button', { name: '对话操作:Second Conversation' }).focus();
|
||||
await page.keyboard.press('Enter');
|
||||
await page.getByRole('menuitem', { name: '重命名', exact: true }).click();
|
||||
const title = page.getByRole('textbox', { name: '对话标题' });
|
||||
await expect(title).toHaveValue('Second Conversation');
|
||||
await title.fill('重命名后的会话');
|
||||
await title.press('Enter');
|
||||
await expect(page.getByRole('dialog')).toHaveCount(0);
|
||||
await expect(header).toContainText('新对话');
|
||||
await sidebar.getByRole('button', { name: '对话操作:重命名后的会话' }).focus();
|
||||
await page.keyboard.press('Enter');
|
||||
await page.getByRole('menuitem', { name: '归档', exact: true }).click();
|
||||
await expect(sidebar.getByRole('button', { name: '重命名后的会话', exact: true })).toHaveCount(0);
|
||||
await sidebar.getByRole('button', { name: '已归档(1)' }).click();
|
||||
await sidebar.getByRole('button', { name: '重命名后的会话', exact: true }).click();
|
||||
await expect(page.getByRole('button', { name: '恢复对话', exact: true })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: '发送', exact: true })).toHaveCount(0);
|
||||
await page.getByRole('button', { name: '恢复对话', exact: true }).click();
|
||||
await expect(header).toContainText('重命名后的会话');
|
||||
await expect(sidebar.getByText('最近对话', { exact: true })).toBeVisible();
|
||||
const requests = (await readState(electronApp)).captured;
|
||||
expect(requests.some((request) => request.path.endsWith('/abort'))).toBe(false);
|
||||
expect(requests.filter((request) => request.method === 'PATCH' && request.path.endsWith('/conversation-pi-second'))
|
||||
.map((request) => request.body)).toEqual([
|
||||
{ title: '重命名后的会话' }, { archived: true }, { archived: false },
|
||||
]);
|
||||
await page.screenshot({ path: 'test-results/coding-session-controls.png' });
|
||||
} finally { await releaseSnapshot(electronApp); }
|
||||
});
|
||||
|
||||
test('managed capabilities expose native xhigh and block unsupported image input', async ({ launchElectronApp }) => {
|
||||
const electronApp = await launchElectronApp({ skipSetup: true });
|
||||
let page = await getStableWindow(electronApp);
|
||||
|
||||
Reference in New Issue
Block a user