feat: add Universal Provider feature (#348)

* feat: add Universal Provider feature

- Add Universal Provider data structures and type definitions
- Implement backend CRUD operations and sync functionality
- Add frontend UI components (UniversalProviderPanel, Card, FormModal)
- Add NewAPI icon and preset configuration
- Support cross-app (Claude/Codex/Gemini) configuration sync
- Add website URL field for providers
- Implement real-time refresh via event notifications
- Add i18n support (Chinese/English/Japanese)

* feat: integrate universal provider presets into add provider dialog

- Add universal provider presets (NewAPI, Custom Gateway) to preset selector
- Show universal presets with Layers icon badge in preset selector
- Open UniversalProviderFormModal when universal preset is clicked
- Pass initialPreset to auto-fill form when opened from add dialog
- Add i18n keys for addSuccess/addFailed messages
- Keep separate universal provider panel for management

* refactor: move universal provider management to add dialog

- Remove Layers button from main navigation header
- Add 'Manage' button next to universal provider presets
- Open UniversalProviderPanel from within add provider dialog
- Add i18n keys for 'manage' in all locales

* style: display universal provider presets on separate line

- Move universal provider section to a new row with border separator
- Add label '统一供应商:' to clarify the section

* style: unify universal provider label style with preset label

- Use FormLabel component for consistent styling
- Add background to 'Manage' button matching preset buttons
- Update icon size and button padding for consistency

* feat: add sync functionality and JSON preview for Universal Provider

* fix: add missing in_failover_queue field to Provider structs

After rebasing to main, the Provider struct gained a new
`in_failover_queue` field. This fix adds the missing field
to the three to_*_provider() methods in UniversalProvider.

* refactor: redesign AddProviderDialog with tab-based layout

- Add tabs to separate app-specific providers and universal providers
- Move "Add Universal Provider" button from panel header to footer
- Remove unused handleAdd callback and clean up imports
- Update emptyHint i18n text to reference the footer button

* fix: append /v1 suffix to Codex base_url in Universal Provider

Codex uses OpenAI-compatible API which requires the /v1 endpoint suffix.
The Universal Provider now automatically appends /v1 to base_url when
generating Codex provider config if not already present.

- Handle trailing slashes to avoid double slashes
- Apply fix to both backend (to_codex_provider) and frontend preview

* feat: auto-sync universal provider to apps on creation

Previously, users had to manually click sync after adding a universal
provider. Now it automatically syncs to Claude/Codex/Gemini on creation,
providing a smoother user experience.

---------

Co-authored-by: Jason <farion1231@gmail.com>
This commit is contained in:
Calcium-Ion
2025-12-26 22:47:24 +08:00
committed by GitHub
parent a24753f074
commit 8fe5c1041a
25 changed files with 2336 additions and 44 deletions
+58
View File
@@ -186,3 +186,61 @@ export interface McpConfigResponse {
configPath: string;
servers: Record<string, McpServer>;
}
// ============================================================================
// 统一供应商(Universal Provider- 跨应用共享配置
// ============================================================================
// 统一供应商的应用启用状态
export interface UniversalProviderApps {
claude: boolean;
codex: boolean;
gemini: boolean;
}
// Claude 模型配置
export interface ClaudeModelConfig {
model?: string;
haikuModel?: string;
sonnetModel?: string;
opusModel?: string;
}
// Codex 模型配置
export interface CodexModelConfig {
model?: string;
reasoningEffort?: string;
}
// Gemini 模型配置
export interface GeminiModelConfig {
model?: string;
}
// 各应用的模型配置
export interface UniversalProviderModels {
claude?: ClaudeModelConfig;
codex?: CodexModelConfig;
gemini?: GeminiModelConfig;
}
// 统一供应商(跨应用共享配置)
export interface UniversalProvider {
id: string;
name: string;
providerType: string; // "newapi" | "custom" 等
apps: UniversalProviderApps;
baseUrl: string;
apiKey: string;
models: UniversalProviderModels;
websiteUrl?: string;
notes?: string;
icon?: string;
iconColor?: string;
meta?: ProviderMeta;
createdAt?: number;
sortIndex?: number;
}
// 统一供应商映射(id -> UniversalProvider
export type UniversalProvidersMap = Record<string, UniversalProvider>;