Skip to content

Commit a685b45

Browse files
committed
fix: stabilize codex config management
1 parent a176922 commit a685b45

8 files changed

Lines changed: 35 additions & 5 deletions

File tree

src/components/providers/CodexSection/CodexSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export function CodexSection({
121121
return (
122122
<Fragment>
123123
<div className="item-title">
124-
{t('ai_providers.codex_item_title')}
124+
{item.name?.trim() || t('ai_providers.codex_item_title')}
125125
{configDisabled && (
126126
<span className="status-badge warning">
127127
{t('ai_providers.config_disabled_badge')}

src/i18n/locales/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@
258258
"codex_empty_title": "No Codex Configuration",
259259
"codex_empty_desc": "Click the button above to add the first configuration",
260260
"codex_item_title": "Codex Configuration",
261+
"codex_config_name_label": "Configuration Name (Optional):",
262+
"codex_config_name_placeholder": "e.g.: Primary account / Backup account",
261263
"codex_add_modal_title": "Add Codex API Configuration",
262264
"codex_add_modal_key_label": "API Key:",
263265
"codex_add_modal_keys_label": "API Keys",

src/i18n/locales/zh-CN.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@
258258
"codex_empty_title": "暂无Codex配置",
259259
"codex_empty_desc": "点击上方按钮添加第一个配置",
260260
"codex_item_title": "Codex配置",
261+
"codex_config_name_label": "配置名称 (可选):",
262+
"codex_config_name_placeholder": "例如: 主账号 / 备用账号",
261263
"codex_add_modal_title": "添加Codex API配置",
262264
"codex_add_modal_key_label": "API密钥:",
263265
"codex_add_modal_keys_label": "API密钥",

src/pages/AiProvidersCodexEditPage.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type LocationState = { fromAiProviders?: boolean } | null;
3030
const buildEmptyForm = (): ProviderFormState => ({
3131
apiKey: '',
3232
apiKeyEntries: [buildApiKeyEntry()],
33+
name: '',
3334
priority: undefined,
3435
prefix: '',
3536
baseUrl: '',
@@ -68,6 +69,7 @@ const normalizeModelEntries = (entries: Array<{ name: string; alias: string }>)
6869

6970
type CodexFormBaseline = {
7071
apiKeyEntries: Array<{ apiKey: string; proxyUrl: string }>;
72+
name: string;
7173
priority: number | null;
7274
prefix: string;
7375
baseUrl: string;
@@ -79,6 +81,7 @@ type CodexFormBaseline = {
7981

8082
const buildCodexBaseline = (form: ProviderFormState): CodexFormBaseline => ({
8183
apiKeyEntries: normalizeCodexApiKeyEntries(form.apiKeyEntries, form.apiKey, form.proxyUrl),
84+
name: String(form.name ?? '').trim(),
8285
priority:
8386
form.priority !== undefined && Number.isFinite(form.priority) ? Math.trunc(form.priority) : null,
8487
prefix: String(form.prefix ?? '').trim(),
@@ -305,6 +308,7 @@ export function AiProvidersCodexEditPage() {
305308
);
306309
const isDirty =
307310
!areCodexApiKeyEntriesEqual(baseline.apiKeyEntries, normalizedApiKeyEntries) ||
311+
baseline.name !== String(form.name ?? '').trim() ||
308312
baseline.priority !== normalizedPriority ||
309313
baseline.prefix !== String(form.prefix ?? '').trim() ||
310314
baseline.baseUrl !== String(form.baseUrl ?? '').trim() ||
@@ -526,9 +530,10 @@ export function AiProvidersCodexEditPage() {
526530
setError('');
527531
try {
528532
const payload: ProviderKeyConfig = {
529-
// 顶层 api-key 只作为旧版接口和列表删除的兼容字段;实际多 key 配置写入 api-key-entries。
533+
// 顶层 api-key 只作为旧版接口和旧配置格式的兼容字段;实际多 key 配置写入 api-key-entries。
530534
apiKey: apiKeyEntries[0]?.apiKey ?? '',
531535
apiKeyEntries,
536+
name: form.name?.trim() || undefined,
532537
priority: form.priority !== undefined ? Math.trunc(form.priority) : undefined,
533538
prefix: form.prefix?.trim() || undefined,
534539
baseUrl,
@@ -724,6 +729,13 @@ export function AiProvidersCodexEditPage() {
724729
<div className="hint">{t('common.invalid_provider_index')}</div>
725730
) : (
726731
<div className={styles.openaiEditForm}>
732+
<Input
733+
label={t('ai_providers.codex_config_name_label')}
734+
placeholder={t('ai_providers.codex_config_name_placeholder')}
735+
value={form.name ?? ''}
736+
onChange={(e) => setForm((prev) => ({ ...prev, name: e.target.value }))}
737+
disabled={disableControls || saving}
738+
/>
727739
<Input
728740
label={t('ai_providers.priority_label')}
729741
hint={t('ai_providers.priority_hint')}

src/pages/AiProvidersPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ export function AiProvidersPage() {
298298
onConfirm: async () => {
299299
try {
300300
if (type === 'codex') {
301-
await providersApi.deleteCodexConfig(getProviderPrimaryApiKey(entry), entry.baseUrl);
301+
await providersApi.deleteCodexConfig(index);
302302
const next = codexConfigs.filter((_, idx) => idx !== index);
303303
setCodexConfigs(next);
304304
updateConfigValue('codex-api-key', next);

src/services/api/providers.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ const buildProviderDeleteQuery = (apiKey: string, baseUrl?: string) => {
3535
return `?${params.toString()}`;
3636
};
3737

38+
const buildProviderDeleteIndexQuery = (index: number) => {
39+
const params = new URLSearchParams();
40+
params.set('index', String(index));
41+
return `?${params.toString()}`;
42+
};
43+
3844
const serializeModelAliases = (models?: ModelAlias[]) =>
3945
Array.isArray(models)
4046
? models
@@ -65,6 +71,7 @@ const serializeApiKeyEntry = (entry: ApiKeyEntry) => {
6571

6672
const serializeProviderKey = (config: ProviderKeyConfig, options?: { includeApiKeyEntries?: boolean }) => {
6773
const payload: Record<string, unknown> = { 'api-key': config.apiKey };
74+
if (config.name?.trim()) payload.name = config.name.trim();
6875
if (options?.includeApiKeyEntries && Array.isArray(config.apiKeyEntries) && config.apiKeyEntries.length) {
6976
payload['api-key-entries'] = config.apiKeyEntries.map((entry) => serializeApiKeyEntry(entry));
7077
}
@@ -192,8 +199,10 @@ export const providersApi = {
192199
value: serializeProviderKey(value, { includeApiKeyEntries: true })
193200
}),
194201

195-
deleteCodexConfig: (apiKey: string, baseUrl?: string) =>
196-
apiClient.delete(`/codex-api-key${buildProviderDeleteQuery(apiKey, baseUrl)}`),
202+
deleteCodexConfig: (target: number | string, baseUrl?: string) =>
203+
typeof target === 'number'
204+
? apiClient.delete(`/codex-api-key${buildProviderDeleteIndexQuery(target)}`)
205+
: apiClient.delete(`/codex-api-key${buildProviderDeleteQuery(target, baseUrl)}`),
197206

198207
async getClaudeConfigs(): Promise<ProviderKeyConfig[]> {
199208
const data = await apiClient.get('/claude-api-key');

src/services/api/transformers.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ const normalizeProviderKeyConfig = (item: unknown): ProviderKeyConfig | null =>
132132
if (apiKeyEntries.length) {
133133
config.apiKeyEntries = apiKeyEntries;
134134
}
135+
const name = record?.name ?? record?.['name'];
136+
if (typeof name === 'string' && name.trim()) {
137+
config.name = name.trim();
138+
}
135139
const priority = record?.priority ?? record?.['priority'];
136140
if (priority !== undefined && priority !== null && String(priority).trim() !== '') {
137141
const parsed = Number(priority);

src/types/provider.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export interface GeminiKeyConfig {
3636
export interface ProviderKeyConfig {
3737
apiKey: string;
3838
apiKeyEntries?: ApiKeyEntry[];
39+
name?: string;
3940
priority?: number;
4041
prefix?: string;
4142
baseUrl?: string;

0 commit comments

Comments
 (0)