fix: optimize ui

This commit is contained in:
07akioni
2026-08-18 18:54:18 +08:00
parent aab839a971
commit b1be9e93cd
4 changed files with 23 additions and 18 deletions
+1 -2
View File
@@ -427,8 +427,7 @@ describe('web e2e: seeded history renders through cold resume', () => {
await fileLink.click()
const dialog = page.getByRole('dialog', { name: 'Couldnt open file' })
await dialog.waitFor({ timeout: 5_000 })
await expect.poll(() => dialog.getByRole('alert').innerText(), { timeout: 5_000 })
.toBe('path open failed: xdg-open is not available')
await expect(dialog.getByText('path open failed: xdg-open is not available')).toBeVisible({ timeout: 5_000 })
await page.getByRole('button', { name: 'Retry' }).click()
await expect.poll(() => openPath.mock.calls.length, { timeout: 5_000 }).toBe(2)
expect(openPath.mock.calls[0]![0].payload).toEqual(openPath.mock.calls[1]![0].payload)
@@ -195,10 +195,3 @@
.modalAction {
min-width: 72px;
}
.modalError {
margin-top: 8px;
font-size: 12px;
line-height: 18px;
color: var(--dsw-alias-state-error-primary);
}
@@ -102,6 +102,20 @@ function openFailureMessage(error: unknown, fallback: string): string {
return message === '' ? fallback : message
}
/**
* Local demo only: `?openFileFail=1` randomly refuses (or lets the Host
* open succeed) so the three dialog cases can be clicked through.
*/
function demoOpenFailure(): Promise<void> | undefined {
if (typeof location === 'undefined') return undefined
if (!new URLSearchParams(location.search).has('openFileFail')) return undefined
const pick = Math.floor(Math.random() * 4)
if (pick === 0) return Promise.reject(new Error('xdg-open is not available'))
if (pick === 1) return Promise.reject('permission denied')
if (pick === 2) return Promise.reject(new Error(''))
return undefined
}
function runningTurnStartTime(timeline: ConversationTimelineSnapshot): number | null {
let latest: number | null = null
for (const turn of timeline.turns.values()) {
@@ -175,7 +189,7 @@ export function ChatView({
const requestOpenFile = useCallback((path: string) => {
const id = ++fileOpenRequest.current
setFileOpenBusy(true)
void Promise.resolve(openFile(path)).then(
void Promise.resolve(demoOpenFailure() ?? openFile(path)).then(
() => {
if (id !== fileOpenRequest.current) return
setFileOpenError(null)
@@ -486,14 +500,13 @@ function FileOpenErrorDialog({
onClose={onClose}
closeLabel={t('close')}
title={t('fileOpen.title')}
description={message}
footer={(
<>
<Button variant="outline" className={css.modalAction} onClick={onClose}>{t('cancel')}</Button>
<Button variant="primary" className={css.modalAction} disabled={busy} onClick={onRetry}>{t('retry')}</Button>
</>
)}
>
<div className={css.modalError} role="alert">{message}</div>
</Modal>
/>
)
}
@@ -984,7 +984,7 @@ describe('ChatView', () => {
await waitFor(() => {
expect(screen.getByRole('dialog', { name: '无法打开文件' })).toBeTruthy()
})
expect(screen.getByRole('alert').textContent).toBe('xdg-open is not available')
expect(screen.getByRole('dialog', { name: '无法打开文件' }).textContent).toContain('xdg-open is not available')
await act(async () => { fireEvent.click(screen.getByRole('button', { name: '重试' })) })
await waitFor(() => {
expect(screen.queryByRole('dialog')).toBeNull()
@@ -1002,7 +1002,7 @@ describe('ChatView', () => {
render(<h.ChatView {...h.props} />)
await act(async () => { h.toolOwners[0]!.openFile('notes.md') })
await waitFor(() => {
expect(screen.getByRole('alert').textContent).toBe('permission denied')
expect(screen.getByRole('dialog', { name: '无法打开文件' }).textContent).toContain('permission denied')
})
fireEvent.click(screen.getByRole('button', { name: '取消' }))
expect(screen.queryByRole('dialog')).toBeNull()
@@ -1017,7 +1017,7 @@ describe('ChatView', () => {
render(<h.ChatView {...h.props} />)
await act(async () => { h.toolOwners[0]!.openFile('empty.ts') })
await waitFor(() => {
expect(screen.getByRole('alert').textContent).toBe('无法打开此文件')
expect(screen.getByRole('dialog', { name: '无法打开文件' }).textContent).toContain('无法打开此文件')
})
})
@@ -1033,7 +1033,7 @@ describe('ChatView', () => {
render(<h.ChatView {...h.props} />)
await act(async () => { h.toolOwners[0]!.openFile('src/a.ts') })
await waitFor(() => {
expect(screen.getByRole('alert').textContent).toBe('first refusal')
expect(screen.getByRole('dialog', { name: '无法打开文件' }).textContent).toContain('first refusal')
})
await act(async () => { fireEvent.click(screen.getByRole('button', { name: '重试' })) })
fireEvent.click(screen.getByRole('button', { name: '取消' }))
@@ -1054,7 +1054,7 @@ describe('ChatView', () => {
render(<h.ChatView {...h.props} />)
await act(async () => { h.toolOwners[0]!.openFile('src/a.ts') })
await waitFor(() => {
expect(screen.getByRole('alert').textContent).toBe('first refusal')
expect(screen.getByRole('dialog', { name: '无法打开文件' }).textContent).toContain('first refusal')
})
await act(async () => { fireEvent.click(screen.getByRole('button', { name: '重试' })) })
fireEvent.click(screen.getByRole('button', { name: '取消' }))