fix(core): clarify and localize existing core errors

This commit is contained in:
wonfen
2026-10-09 10:03:12 +08:00
parent cb751052a4
commit 4337bd8575
33 changed files with 151 additions and 23 deletions
@@ -0,0 +1,67 @@
import { createInstance } from 'i18next'
import { createElement } from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import { I18nextProvider } from 'react-i18next'
import { afterEach, expect, it, vi } from 'vitest'
import settings from '@/locales/en/settings.json'
import {
getSnapshotNotices,
hideNotice,
showNotice,
syncSidecarFailure,
} from '@/services/notice-service'
import { NoticeManager } from './notice-manager'
vi.mock('react', async (importOriginal) => ({
...(await importOriginal<typeof import('react')>()),
useSyncExternalStore: (_subscribe: unknown, snapshot: () => unknown) =>
snapshot(),
}))
vi.mock('@/utils/open-external-url', () => ({ openExternalUrl: vi.fn() }))
afterEach(() => {
getSnapshotNotices().forEach(({ id }) => hideNotice(id))
})
it.each([
[
'startup',
'process verge-mihomo remains after IPC failure; refusing a second core',
],
[
'restart',
'process verge-mihomo-alpha remains after IPC failure; refusing a second core',
],
[
'sidecar',
'Service core rejected: permission denied; Sidecar fallback failed: process verge-mihomo.exe (PID 123) is still running; refusing a second core',
],
])(
'explains an occupied core during %s and preserves diagnostics',
async (operation, detail) => {
if (operation === 'startup') {
showNotice.error('settings.feedback.errors.clash.startFailed', detail)
} else if (operation === 'restart') {
showNotice.error({ code: 'CORE_RESTART_FAILED', detail })
} else {
syncSidecarFailure({ revision: 1, detail })
}
const i18n = createInstance()
await i18n.init({
lng: 'en',
resources: { en: { translation: { settings } } },
})
const html = renderToStaticMarkup(
createElement(I18nextProvider, { i18n }, createElement(NoticeManager)),
)
expect(html).toContain('a core process is already running')
expect(html).toContain('Close the related app or stop the leftover process')
expect(html).toContain(detail)
if (operation === 'sidecar') {
expect(html).toContain('service-core-permissions')
expect(html).toContain('PID 123')
}
},
)
+4 -5
View File
@@ -70,8 +70,8 @@ const resolveNoticeMessage = (
const detail = i18n.params?.message
const existingCore =
notice.code === 'SERVICE_SIDECAR_FAILED' && typeof detail === 'string'
? /process verge-mihomo(?:-alpha)?(?:\.exe)? \(PID (\d+)\) is still running; refusing a second core\s*$/.exec(
typeof detail === 'string'
? /process verge-mihomo(?:-alpha|-al)?(?:\.exe)? (?:\(PID (\d+)\) is still running|remains after IPC failure); refusing a second core\s*$/.exec(
detail,
)
: null
@@ -101,9 +101,8 @@ const resolveNoticeMessage = (
</Link>
</Box>
)}
{t('settings.feedback.errors.clashService.coreAlreadyRunning', {
pid: existingCore[1],
})}
{t('settings.feedback.errors.clashService.coreAlreadyRunning')}
{existingCore[1] && <Box sx={{ mt: 1 }}>PID {existingCore[1]}</Box>}
<Box component="details" sx={{ mt: 1 }}>
<Box component="summary" sx={{ cursor: 'pointer' }}>
{t('shared.feedback.errors.details')}