[codex] add vendor code entry presets follow-up (#363)
* address coding plan review comments * add more vendor code entry presets
This commit is contained in:
@@ -28,6 +28,7 @@ import {
|
||||
type SiteForm,
|
||||
} from './helpers/sitesEditor.js';
|
||||
import {
|
||||
detectSiteInitializationPreset,
|
||||
getSiteInitializationPreset,
|
||||
listSiteInitializationPresets,
|
||||
} from '../../shared/siteInitializationPresets.js';
|
||||
@@ -388,7 +389,7 @@ export default function Sites() {
|
||||
const openEdit = (site: SiteRow) => {
|
||||
setEditor({ mode: 'edit', editingSiteId: site.id });
|
||||
setForm(siteFormFromSite(site));
|
||||
setSelectedInitializationPresetId(null);
|
||||
setSelectedInitializationPresetId(detectSiteInitializationPreset(site.url, site.platform)?.id || null);
|
||||
scrollToEditorTop();
|
||||
// Load disabled models and discovered models independently so a best-effort
|
||||
// availability fetch cannot wipe the existing disabled-model state.
|
||||
|
||||
@@ -113,4 +113,67 @@ describe('Accounts CodingPlan initialization', () => {
|
||||
root?.unmount();
|
||||
}
|
||||
});
|
||||
|
||||
it('preloads vendor-specific recommendations for new code presets such as DeepSeek', async () => {
|
||||
apiMock.getSites.mockResolvedValue([
|
||||
{ id: 11, name: 'DeepSeek Official', url: 'https://api.deepseek.com/v1', platform: 'openai', status: 'active' },
|
||||
]);
|
||||
apiMock.addAccount.mockResolvedValue({
|
||||
id: 19,
|
||||
siteId: 11,
|
||||
tokenType: 'apikey',
|
||||
queued: false,
|
||||
});
|
||||
|
||||
let root!: ReactTestRenderer;
|
||||
try {
|
||||
await act(async () => {
|
||||
root = create(
|
||||
<MemoryRouter initialEntries={['/accounts?segment=apikey&create=1&siteId=11&initPreset=deepseek-openai']}>
|
||||
<ToastProvider>
|
||||
<Accounts />
|
||||
</ToastProvider>
|
||||
</MemoryRouter>,
|
||||
);
|
||||
});
|
||||
await flushMicrotasks();
|
||||
|
||||
const rendered = JSON.stringify(root.toJSON());
|
||||
expect(rendered).toContain('DeepSeek / OpenAI');
|
||||
expect(rendered).toContain('deepseek-chat');
|
||||
expect(rendered).toContain('deepseek-reasoner');
|
||||
|
||||
const tokenInput = root.root.find((node) => (
|
||||
node.type === 'textarea'
|
||||
&& node.props.placeholder === '粘贴 API Key'
|
||||
));
|
||||
const addButton = root.root.find((node) => (
|
||||
node.type === 'button'
|
||||
&& typeof node.props.onClick === 'function'
|
||||
&& collectText(node).includes('添加连接')
|
||||
));
|
||||
|
||||
await act(async () => {
|
||||
tokenInput.props.onChange({ target: { value: 'sk-deepseek-demo' } });
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
await addButton.props.onClick();
|
||||
});
|
||||
await flushMicrotasks();
|
||||
|
||||
expect(apiMock.addAccount).toHaveBeenCalledWith(expect.objectContaining({
|
||||
siteId: 11,
|
||||
accessToken: 'sk-deepseek-demo',
|
||||
credentialMode: 'apikey',
|
||||
skipModelFetch: true,
|
||||
}));
|
||||
expect(apiMock.addAccountAvailableModels).toHaveBeenCalledWith(
|
||||
19,
|
||||
['deepseek-chat', 'deepseek-reasoner'],
|
||||
);
|
||||
} finally {
|
||||
root?.unmount();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -219,6 +219,15 @@ describe('Sites create redirect', () => {
|
||||
expect.objectContaining({ label: '阿里云 CodingPlan / Claude' }),
|
||||
expect.objectContaining({ label: '智谱 Coding Plan / OpenAI' }),
|
||||
expect.objectContaining({ label: '智谱 Coding Plan / Claude' }),
|
||||
expect.objectContaining({ label: 'DeepSeek / OpenAI' }),
|
||||
expect.objectContaining({ label: 'DeepSeek / Claude' }),
|
||||
expect.objectContaining({ label: 'Moonshot(Kimi) / OpenAI' }),
|
||||
expect.objectContaining({ label: 'Moonshot(Kimi) / Claude' }),
|
||||
expect.objectContaining({ label: 'MiniMax / OpenAI' }),
|
||||
expect.objectContaining({ label: 'MiniMax / Claude' }),
|
||||
expect.objectContaining({ label: 'ModelScope / OpenAI' }),
|
||||
expect.objectContaining({ label: 'ModelScope / Claude' }),
|
||||
expect.objectContaining({ label: '豆包 Coding Plan / OpenAI' }),
|
||||
]),
|
||||
);
|
||||
} finally {
|
||||
@@ -554,4 +563,54 @@ describe('Sites create redirect', () => {
|
||||
|
||||
root.unmount();
|
||||
});
|
||||
|
||||
it('re-selects the matching vendor preset when editing an existing vendor-specific site', async () => {
|
||||
apiMock.getSites.mockResolvedValue([
|
||||
{
|
||||
id: 36,
|
||||
name: 'DeepSeek Official',
|
||||
url: 'https://api.deepseek.com/v1',
|
||||
platform: 'openai',
|
||||
status: 'active',
|
||||
},
|
||||
]);
|
||||
|
||||
let root!: ReactTestRenderer;
|
||||
try {
|
||||
await act(async () => {
|
||||
root = create(
|
||||
<ToastProvider>
|
||||
<MemoryRouter initialEntries={['/sites']}>
|
||||
<Routes>
|
||||
<Route path="/sites" element={<Sites />} />
|
||||
</Routes>
|
||||
</MemoryRouter>
|
||||
</ToastProvider>,
|
||||
);
|
||||
});
|
||||
await flushMicrotasks();
|
||||
|
||||
const editButton = root.root.find((node) => (
|
||||
node.type === 'button'
|
||||
&& typeof node.props.onClick === 'function'
|
||||
&& collectText(node).includes('编辑')
|
||||
));
|
||||
|
||||
await act(async () => {
|
||||
editButton.props.onClick();
|
||||
});
|
||||
await flushMicrotasks();
|
||||
|
||||
const platformSelect = root.root.findAllByType(ModernSelect).at(-1);
|
||||
const presetAlert = root.root.find((node) => (
|
||||
typeof node.props.className === 'string'
|
||||
&& node.props.className.includes('alert alert-info')
|
||||
));
|
||||
expect(platformSelect?.props.value).toBe('preset:deepseek-openai');
|
||||
expect(collectText(presetAlert)).toContain('已应用官方预设');
|
||||
expect(collectText(presetAlert)).toContain('DeepSeek / OpenAI');
|
||||
} finally {
|
||||
root?.unmount();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user