fix(providers): preserve custom endpoints in meta during add/edit operations

Fixed two critical data loss bugs where user-added custom endpoints were discarded:

1. **AddProviderDialog**: Form submission ignored values.meta from ProviderForm and
   re-inferred URLs only from presets/config, causing loss of endpoints added via
   speed test modal. Now prioritizes form-collected meta and uses fallback inference
   only when custom_endpoints is missing.

2. **ProviderForm**: Edit mode always returned initialData.meta, discarding any
   changes made in the speed test modal. Now uses mergeProviderMeta to properly
   merge customEndpointsMap with existing meta fields.

Changes:
- Extract mergeProviderMeta utility to handle meta field merging logic
- Preserve other meta fields (e.g., usage_script) during endpoint updates
- Unify new/edit code paths to use consistent meta handling
- Add comprehensive unit tests for meta merging scenarios
- Add integration tests for AddProviderDialog submission flow

Impact:
- Third-party and custom providers can now reliably manage multiple endpoints
- Edit operations correctly reflect user modifications
- No data loss for existing meta fields like usage_script
This commit is contained in:
Jason
2025-10-28 20:28:11 +08:00
parent 1841f8b462
commit 7d56aed543
5 changed files with 318 additions and 75 deletions

View File

@@ -6,13 +6,14 @@ import { Button } from "@/components/ui/button";
import { Form } from "@/components/ui/form";
import { providerSchema, type ProviderFormData } from "@/lib/schemas/provider";
import type { AppType } from "@/lib/api";
import type { ProviderCategory, CustomEndpoint, ProviderMeta } from "@/types";
import type { ProviderCategory, ProviderMeta } from "@/types";
import { providerPresets, type ProviderPreset } from "@/config/providerPresets";
import {
codexProviderPresets,
type CodexProviderPreset,
} from "@/config/codexProviderPresets";
import { applyTemplateValues } from "@/utils/providerConfigUtils";
import { mergeProviderMeta } from "@/utils/providerMetaUtils";
import CodexConfigEditor from "./CodexConfigEditor";
import { CommonConfigEditor } from "./CommonConfigEditor";
import { ProviderPresetSelector } from "./ProviderPresetSelector";
@@ -324,12 +325,9 @@ export function ProviderForm({
}
// 处理 meta 字段(新建与编辑使用不同策略)
if (initialData?.meta) {
// 编辑模式:后端已通过 API 更新 meta直接使用原有值
payload.meta = initialData.meta;
} else if (customEndpointsMap) {
// 新建模式:从表单收集的自定义端点打包到 meta
payload.meta = { custom_endpoints: customEndpointsMap };
const mergedMeta = mergeProviderMeta(initialData?.meta, customEndpointsMap);
if (mergedMeta) {
payload.meta = mergedMeta;
}
onSubmit(payload);
@@ -580,7 +578,5 @@ export function ProviderForm({
export type ProviderFormValues = ProviderFormData & {
presetId?: string;
presetCategory?: ProviderCategory;
meta?: {
custom_endpoints?: Record<string, CustomEndpoint>;
};
meta?: ProviderMeta;
};