mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
Merge pull request #2512 from deepseek-harness/codex/2503-english-onboarding-copy
fix(web): add English onboarding copy
This commit is contained in:
@@ -26,7 +26,7 @@ export function OnboardingModal({
|
||||
useEffect(() => {
|
||||
const appRoot = document.getElementById('root')
|
||||
if (appRoot === null) return
|
||||
const previous = appRoot.inert === true
|
||||
const previous = appRoot.inert
|
||||
appRoot.inert = true
|
||||
return () => { appRoot.inert = previous }
|
||||
}, [])
|
||||
@@ -41,7 +41,7 @@ export function OnboardingModal({
|
||||
title={title}
|
||||
onClose={ignoreImplicitDismiss}
|
||||
headless
|
||||
className={css['dialog'] ?? ''}
|
||||
className={css.dialog as string}
|
||||
>
|
||||
<div className={css.content}>
|
||||
<h2 ref={titleRef} className={css.title} tabIndex={focusTitle ? -1 : undefined}>{title}</h2>
|
||||
|
||||
@@ -103,7 +103,7 @@ export const en = {
|
||||
export type ModelsKey = keyof typeof en
|
||||
|
||||
/** Chinese strings (same keys as {@link en}). */
|
||||
export const zh: typeof en = {
|
||||
export const zh: { [Key in keyof typeof en]: string } = {
|
||||
nav: '模型',
|
||||
title: '模型',
|
||||
intro: '填入各提供方的 API 密钥即可使用其模型。',
|
||||
|
||||
@@ -18,8 +18,8 @@ export const WELCOME_NOTICE_COPY = {
|
||||
continueLabel: '继续',
|
||||
},
|
||||
en: {
|
||||
title: '内测声明',
|
||||
body: 'DeepSeek Harness 目前的 0.1 版本仍处在面向 Harness 开发者进行测试的阶段,还有许多地方需要持续改进和打磨,希望听取广大开发者的反馈建议。预计 DeepSeek Harness 的核心插件以及基础 API 都会在接下来的一段时间内快速迭代、持续演化。\n\n我们期待与全球开发者一起,在开源、开放、可复用、可组合的基础设施之上,共同探索智能上限。欢迎全球 Harness 开发者加入 DSH 插件生态。',
|
||||
continueLabel: '继续',
|
||||
title: 'Internal Testing Notice',
|
||||
body: "DeepSeek Harness 0.1 remains in testing for Harness developers. Many areas need further improvement, and we welcome feedback from the developer community. DeepSeek Harness's core plugins and foundational APIs will continue to evolve rapidly over the coming months.\n\nWe look forward to exploring the limits of intelligence with developers around the world, building on open-source, open, reusable, and composable infrastructure. We welcome Harness developers everywhere to join the DSH plugin ecosystem.",
|
||||
continueLabel: 'Continue',
|
||||
},
|
||||
} as const
|
||||
|
||||
@@ -14,7 +14,7 @@ import { WelcomeNotice } from '../src/client/WelcomeNotice.tsx'
|
||||
// the shipped Chinese copy, so they state the browser they assume.
|
||||
usePinnedBrowserLanguages('zh-CN')
|
||||
|
||||
async function bench() {
|
||||
async function bench(isLoopback = true) {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SlotRegistry).await()
|
||||
const locale = new LocaleRuntime(ctx)
|
||||
@@ -24,7 +24,7 @@ async function bench() {
|
||||
new TestRemote(ctx)
|
||||
// The apply path only captures the wire face; no call leaves this fake
|
||||
// until a section actually loads.
|
||||
ctx.provide('connection', { api: {}, isLoopback: true } as never)
|
||||
ctx.provide('connection', { api: {}, isLoopback } as never)
|
||||
return { ctx, slots: ctx.get('slots') as SlotRegistry, locale }
|
||||
}
|
||||
|
||||
@@ -142,6 +142,22 @@ describe('ui-settings-models apply', () => {
|
||||
expect(() => b.locale.register('settings.models', 'zh', {})).not.toThrow()
|
||||
expect(() => b.locale.register('settings.models', 'en', {})).not.toThrow()
|
||||
})
|
||||
|
||||
it('keeps remote-browser acknowledgement in process memory', async () => {
|
||||
const b = await bench(false)
|
||||
declare(b.slots)
|
||||
await b.ctx.plugin({ inject: [...inject], apply }).await()
|
||||
const entry = b.slots.entries('settings.onboarding')
|
||||
.find(candidate => candidate.options.id === 'welcome-notice')!
|
||||
const injected = (
|
||||
entry.inject as unknown as () => import('../src/client/WelcomeNotice.tsx').WelcomeNoticeInjected
|
||||
)()
|
||||
|
||||
await injected.controller.load()
|
||||
expect(injected.controller.store.getSnapshot()).toEqual({
|
||||
status: 'ready', acknowledged: false, error: null,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('pushed invalidations', () => {
|
||||
|
||||
@@ -146,6 +146,13 @@ function harness(options: {
|
||||
}
|
||||
|
||||
describe('DeepSeekOnboardingDialog', () => {
|
||||
it('renders when the shell root is absent', async () => {
|
||||
const h = harness()
|
||||
document.getElementById('root')!.remove()
|
||||
render(<DeepSeekOnboardingDialog {...h.props} />)
|
||||
expect(await screen.findByRole('dialog', { name: en.onboardingTitle })).toBeTruthy()
|
||||
})
|
||||
|
||||
it('loads a credential-only modal, inerts the product, and focuses the key', async () => {
|
||||
const h = harness()
|
||||
render(<DeepSeekOnboardingDialog {...h.props} />)
|
||||
@@ -185,22 +192,6 @@ describe('DeepSeekOnboardingDialog', () => {
|
||||
expect(h.set).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('stores only the official credential, refreshes, and completes without opening Settings', async () => {
|
||||
const h = harness()
|
||||
render(<DeepSeekOnboardingDialog {...h.props} />)
|
||||
await screen.findByRole('dialog')
|
||||
fireEvent.change(screen.getByLabelText(en.keyInput), { target: { value: ' sk-live ' } })
|
||||
fireEvent.click(screen.getByRole('button', { name: en.onboardingSave }))
|
||||
await waitFor(() => {
|
||||
expect(h.set).toHaveBeenCalledWith({ ref: 'DEEPSEEK_API_KEY', value: 'sk-live' })
|
||||
})
|
||||
expect(h.mutate).not.toHaveBeenCalled()
|
||||
expect(h.openSection).not.toHaveBeenCalled()
|
||||
await waitFor(() => { expect(h.complete).toHaveBeenCalledOnce() })
|
||||
expect(screen.queryByRole('dialog')).toBeNull()
|
||||
expect(document.getElementById('root')?.inert).toBe(false)
|
||||
})
|
||||
|
||||
it('keeps the modal open and reports rejected and failed credential writes', async () => {
|
||||
for (const [options, message] of [
|
||||
[{ setFailure: 'credential was rejected' }, 'credential was rejected'],
|
||||
|
||||
@@ -62,7 +62,11 @@ function mount(version?: string, mutateImpl: () => Promise<unknown> = () => Prom
|
||||
|
||||
describe('WelcomeNotice', () => {
|
||||
it('uses the exact owner copy in both GUI locales', () => {
|
||||
expect(WELCOME_NOTICE_COPY.en).toEqual(WELCOME_NOTICE_COPY.zh)
|
||||
expect(WELCOME_NOTICE_COPY.en).toEqual({
|
||||
title: 'Internal Testing Notice',
|
||||
body: "DeepSeek Harness 0.1 remains in testing for Harness developers. Many areas need further improvement, and we welcome feedback from the developer community. DeepSeek Harness's core plugins and foundational APIs will continue to evolve rapidly over the coming months.\n\nWe look forward to exploring the limits of intelligence with developers around the world, building on open-source, open, reusable, and composable infrastructure. We welcome Harness developers everywhere to join the DSH plugin ecosystem.",
|
||||
continueLabel: 'Continue',
|
||||
})
|
||||
expect(en.welcomeBody).toBe(WELCOME_NOTICE_COPY.en.body)
|
||||
expect(zh.welcomeBody).toBe(WELCOME_NOTICE_COPY.zh.body)
|
||||
})
|
||||
|
||||
@@ -91,7 +91,7 @@ describe('WelcomeNoticeStore', () => {
|
||||
|
||||
const nonError = new WelcomeNoticeStore({
|
||||
// Durable/wire failures are unknown; exercise containment of a non-Error rejection.
|
||||
settings: { describe: () => Promise.reject('offline string') },
|
||||
settings: { describe: () => Promise.reject(new Error('offline string')) },
|
||||
} as never)
|
||||
await nonError.load()
|
||||
expect(nonError.store.getSnapshot().error).toBe('offline string')
|
||||
|
||||
@@ -243,6 +243,8 @@ export default defineConfig({
|
||||
'packages/client/ui-workspace/src/client/index.ts',
|
||||
'packages/test-support/client-runtime/src/translate.ts',
|
||||
'packages/client/ui-primitives/src/JsonTree.tsx',
|
||||
'packages/client/ui-settings-models/src/client/DeepSeekOnboardingDialog.tsx',
|
||||
'packages/client/ui-settings-models/src/client/welcome-store.ts',
|
||||
'packages/extensions/*/src/**/*.ts',
|
||||
'packages/extensions/*/src/**/*.tsx',
|
||||
// Typert generator: correctness is pinned by its fixture suites and
|
||||
|
||||
Reference in New Issue
Block a user