fix: provider settings UI, OpenRouter model field, merge resolution, i18n
This commit is contained in:
@@ -72,16 +72,19 @@ function fallbackModelsEqual(a?: string[], b?: string[]): boolean {
|
|||||||
return left.length === right.length && left.every((model, index) => model === right[index]);
|
return left.length === right.length && left.every((model, index) => model === right[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAuthModeLabel(authMode: ProviderAccount['authMode']): string {
|
function getAuthModeLabel(
|
||||||
|
authMode: ProviderAccount['authMode'],
|
||||||
|
t: (key: string) => string
|
||||||
|
): string {
|
||||||
switch (authMode) {
|
switch (authMode) {
|
||||||
case 'api_key':
|
case 'api_key':
|
||||||
return 'API Key';
|
return t('aiProviders.authModes.apiKey');
|
||||||
case 'oauth_device':
|
case 'oauth_device':
|
||||||
return 'OAuth Device';
|
return t('aiProviders.authModes.oauthDevice');
|
||||||
case 'oauth_browser':
|
case 'oauth_browser':
|
||||||
return 'OAuth Browser';
|
return t('aiProviders.authModes.oauthBrowser');
|
||||||
case 'local':
|
case 'local':
|
||||||
return 'Local';
|
return t('aiProviders.authModes.local');
|
||||||
default:
|
default:
|
||||||
return authMode;
|
return authMode;
|
||||||
}
|
}
|
||||||
@@ -174,14 +177,6 @@ export function ProvidersSettings() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{accounts.length > 0 && (
|
|
||||||
<ProviderAccountsOverview
|
|
||||||
accounts={accounts}
|
|
||||||
vendors={vendors}
|
|
||||||
defaultAccountId={defaultAccountId}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<Button size="sm" onClick={() => setShowAddDialog(true)}>
|
<Button size="sm" onClick={() => setShowAddDialog(true)}>
|
||||||
<Plus className="h-4 w-4 mr-2" />
|
<Plus className="h-4 w-4 mr-2" />
|
||||||
@@ -259,58 +254,6 @@ export function ProvidersSettings() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ProviderAccountsOverview({
|
|
||||||
accounts,
|
|
||||||
vendors,
|
|
||||||
defaultAccountId,
|
|
||||||
}: {
|
|
||||||
accounts: ProviderAccount[];
|
|
||||||
vendors: ProviderVendorInfo[];
|
|
||||||
defaultAccountId: string | null;
|
|
||||||
}) {
|
|
||||||
const vendorMap = new Map(vendors.map((vendor) => [vendor.id, vendor]));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card>
|
|
||||||
<CardHeader className="pb-3">
|
|
||||||
<CardTitle>Provider Accounts</CardTitle>
|
|
||||||
<CardDescription>
|
|
||||||
Account-aware provider metadata is now available and will back the next UI migration step.
|
|
||||||
</CardDescription>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="space-y-3">
|
|
||||||
{accounts.map((account) => {
|
|
||||||
const vendor = vendorMap.get(account.vendorId);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={account.id}
|
|
||||||
className="flex items-center justify-between rounded-lg border p-3"
|
|
||||||
>
|
|
||||||
<div className="min-w-0">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span className="font-medium truncate">{account.label}</span>
|
|
||||||
<Badge variant="secondary">{vendor?.name || account.vendorId}</Badge>
|
|
||||||
<Badge variant="outline">{getAuthModeLabel(account.authMode)}</Badge>
|
|
||||||
{account.id === defaultAccountId || account.isDefault ? (
|
|
||||||
<Badge>Default</Badge>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
<div className="mt-1 text-sm text-muted-foreground truncate">
|
|
||||||
{account.model || 'No model selected'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="text-xs text-muted-foreground">
|
|
||||||
{vendor?.supportsMultipleAccounts ? 'multi-account ready' : 'singleton vendor'}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ProviderCardProps {
|
interface ProviderCardProps {
|
||||||
item: ProviderListItem;
|
item: ProviderListItem;
|
||||||
allProviders: ProviderListItem[];
|
allProviders: ProviderListItem[];
|
||||||
@@ -466,9 +409,14 @@ function ProviderCard({
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="font-semibold">{account.label}</span>
|
<span className="font-semibold">{account.label}</span>
|
||||||
<Badge variant="secondary">{vendor?.name || account.vendorId}</Badge>
|
<Badge variant="secondary">{vendor?.name || account.vendorId}</Badge>
|
||||||
<Badge variant="outline">{getAuthModeLabel(account.authMode)}</Badge>
|
<Badge variant="outline">{getAuthModeLabel(account.authMode, t)}</Badge>
|
||||||
|
</div>
|
||||||
|
<div className="mt-1 space-y-0.5">
|
||||||
|
<p className="text-xs text-muted-foreground capitalize">{account.vendorId}</p>
|
||||||
|
<p className="text-xs text-muted-foreground truncate">
|
||||||
|
{t('aiProviders.dialog.modelId')}: {account.model || t('aiProviders.card.none')}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-xs text-muted-foreground capitalize">{account.vendorId}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,6 +13,19 @@
|
|||||||
"aiProviders": {
|
"aiProviders": {
|
||||||
"title": "AI Providers",
|
"title": "AI Providers",
|
||||||
"description": "Configure your AI model providers and API keys",
|
"description": "Configure your AI model providers and API keys",
|
||||||
|
"overview": {
|
||||||
|
"title": "Provider Accounts",
|
||||||
|
"description": "A summary of the provider accounts and models currently configured.",
|
||||||
|
"noModelSelected": "No model selected",
|
||||||
|
"multiAccountReady": "Multi-account ready",
|
||||||
|
"singletonVendor": "Single-account vendor"
|
||||||
|
},
|
||||||
|
"authModes": {
|
||||||
|
"apiKey": "API Key",
|
||||||
|
"oauthDevice": "OAuth Device",
|
||||||
|
"oauthBrowser": "OAuth Browser",
|
||||||
|
"local": "Local"
|
||||||
|
},
|
||||||
"sections": {
|
"sections": {
|
||||||
"model": "Model Settings",
|
"model": "Model Settings",
|
||||||
"fallback": "Fallback Settings"
|
"fallback": "Fallback Settings"
|
||||||
|
|||||||
@@ -13,6 +13,19 @@
|
|||||||
"aiProviders": {
|
"aiProviders": {
|
||||||
"title": "AI プロバイダー",
|
"title": "AI プロバイダー",
|
||||||
"description": "AI モデルプロバイダーと API キーを設定",
|
"description": "AI モデルプロバイダーと API キーを設定",
|
||||||
|
"overview": {
|
||||||
|
"title": "プロバイダーアカウント",
|
||||||
|
"description": "現在設定されているプロバイダーアカウントとモデルの概要です。",
|
||||||
|
"noModelSelected": "モデル未選択",
|
||||||
|
"multiAccountReady": "複数アカウント対応",
|
||||||
|
"singletonVendor": "単一アカウントのプロバイダー"
|
||||||
|
},
|
||||||
|
"authModes": {
|
||||||
|
"apiKey": "API キー",
|
||||||
|
"oauthDevice": "OAuth デバイス",
|
||||||
|
"oauthBrowser": "OAuth ブラウザ",
|
||||||
|
"local": "ローカル"
|
||||||
|
},
|
||||||
"sections": {
|
"sections": {
|
||||||
"model": "モデル設定",
|
"model": "モデル設定",
|
||||||
"fallback": "フォールバック設定"
|
"fallback": "フォールバック設定"
|
||||||
|
|||||||
@@ -13,6 +13,19 @@
|
|||||||
"aiProviders": {
|
"aiProviders": {
|
||||||
"title": "AI 模型提供商",
|
"title": "AI 模型提供商",
|
||||||
"description": "配置 AI 模型提供商和 API 密钥",
|
"description": "配置 AI 模型提供商和 API 密钥",
|
||||||
|
"overview": {
|
||||||
|
"title": "提供商账户",
|
||||||
|
"description": "这里汇总当前已配置的 provider 账户与模型信息。",
|
||||||
|
"noModelSelected": "未选择模型",
|
||||||
|
"multiAccountReady": "支持多账户",
|
||||||
|
"singletonVendor": "单例提供商"
|
||||||
|
},
|
||||||
|
"authModes": {
|
||||||
|
"apiKey": "API 密钥",
|
||||||
|
"oauthDevice": "OAuth 设备登录",
|
||||||
|
"oauthBrowser": "OAuth 浏览器登录",
|
||||||
|
"local": "本地"
|
||||||
|
},
|
||||||
"sections": {
|
"sections": {
|
||||||
"model": "模型配置",
|
"model": "模型配置",
|
||||||
"fallback": "回退配置"
|
"fallback": "回退配置"
|
||||||
|
|||||||
Reference in New Issue
Block a user