feat(settings): protect model provider deletion and cascade credential updates
- Block deletion of a model provider when it is referenced by any agent, returning an error that lists the agent names so the user knows what to unlink first - When a provider's api_url or api_key is updated, automatically propagate the new credentials to all dependent agents: updates env_json in the database and patches on-disk config files (Claude Code settings.json, Gemini settings.json, Codex auth.json + config.toml, OpenCode auth.json) using the same field names and structure as the agent settings UI - Fix error message display in provider dialogs for both Tauri and web transports, which throw plain objects rather than Error instances Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -89,8 +89,14 @@ export function AddModelProviderDialog({
|
||||
toast.success(t("createSuccess"))
|
||||
handleOpenChange(false)
|
||||
onProviderAdded()
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err)
|
||||
} catch (err: unknown) {
|
||||
const raw = err as Record<string, unknown>
|
||||
const msg =
|
||||
typeof raw?.message === "string"
|
||||
? raw.message
|
||||
: err instanceof Error
|
||||
? err.message
|
||||
: String(err)
|
||||
setError(msg)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
|
||||
@@ -97,8 +97,14 @@ export function EditModelProviderDialog({
|
||||
toast.success(t("editSuccess"))
|
||||
handleOpenChange(false)
|
||||
onProviderUpdated()
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err)
|
||||
} catch (err: unknown) {
|
||||
const raw = err as Record<string, unknown>
|
||||
const msg =
|
||||
typeof raw?.message === "string"
|
||||
? raw.message
|
||||
: err instanceof Error
|
||||
? err.message
|
||||
: String(err)
|
||||
setError(msg)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
|
||||
@@ -72,9 +72,21 @@ export function ModelProviderSettings() {
|
||||
toast.success(t("deleteSuccess"))
|
||||
setDeleteTarget(null)
|
||||
await loadProviders()
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err)
|
||||
toast.error(msg)
|
||||
} catch (err: unknown) {
|
||||
const raw = err as Record<string, unknown>
|
||||
const msg =
|
||||
typeof raw?.message === "string"
|
||||
? raw.message
|
||||
: err instanceof Error
|
||||
? err.message
|
||||
: String(err)
|
||||
const prefix = "PROVIDER_IN_USE:"
|
||||
if (msg.includes(prefix)) {
|
||||
const agentNames = msg.substring(msg.indexOf(prefix) + prefix.length)
|
||||
toast.error(t("deleteBlockedByAgent", { agents: agentNames }))
|
||||
} else {
|
||||
toast.error(msg)
|
||||
}
|
||||
}
|
||||
}, [deleteTarget, loadProviders, t])
|
||||
|
||||
|
||||
@@ -1849,6 +1849,7 @@
|
||||
"deleteSuccess": "تم حذف المزود.",
|
||||
"deleteConfirmTitle": "حذف المزود",
|
||||
"deleteConfirmMessage": "سيتم حذف المزود \"{name}\" نهائياً. هل أنت متأكد؟",
|
||||
"deleteBlockedByAgent": "{agents} يستخدم هذا المزود. يرجى إلغاء الربط قبل الحذف.",
|
||||
"cancel": "إلغاء",
|
||||
"delete": "حذف",
|
||||
"create": "إنشاء",
|
||||
|
||||
@@ -1849,6 +1849,7 @@
|
||||
"deleteSuccess": "Anbieter gelöscht.",
|
||||
"deleteConfirmTitle": "Anbieter löschen",
|
||||
"deleteConfirmMessage": "Der Anbieter \"{name}\" wird dauerhaft gelöscht. Sind Sie sicher?",
|
||||
"deleteBlockedByAgent": "{agents} verwendet diesen Anbieter. Bitte trennen Sie die Verbindung vor dem Löschen.",
|
||||
"cancel": "Abbrechen",
|
||||
"delete": "Löschen",
|
||||
"create": "Erstellen",
|
||||
|
||||
@@ -1849,6 +1849,7 @@
|
||||
"deleteSuccess": "Provider deleted.",
|
||||
"deleteConfirmTitle": "Delete Provider",
|
||||
"deleteConfirmMessage": "This will permanently delete the provider \"{name}\". Are you sure?",
|
||||
"deleteBlockedByAgent": "{agents} is currently using this provider. Please unlink before deleting.",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete",
|
||||
"create": "Create",
|
||||
|
||||
@@ -1849,6 +1849,7 @@
|
||||
"deleteSuccess": "Proveedor eliminado.",
|
||||
"deleteConfirmTitle": "Eliminar Proveedor",
|
||||
"deleteConfirmMessage": "Esto eliminará permanentemente el proveedor \"{name}\". ¿Está seguro?",
|
||||
"deleteBlockedByAgent": "{agents} está usando este proveedor. Desvincúlelo antes de eliminarlo.",
|
||||
"cancel": "Cancelar",
|
||||
"delete": "Eliminar",
|
||||
"create": "Crear",
|
||||
|
||||
@@ -1849,6 +1849,7 @@
|
||||
"deleteSuccess": "Fournisseur supprimé.",
|
||||
"deleteConfirmTitle": "Supprimer le Fournisseur",
|
||||
"deleteConfirmMessage": "Le fournisseur \"{name}\" sera définitivement supprimé. Êtes-vous sûr ?",
|
||||
"deleteBlockedByAgent": "{agents} utilise ce fournisseur. Veuillez le dissocier avant de supprimer.",
|
||||
"cancel": "Annuler",
|
||||
"delete": "Supprimer",
|
||||
"create": "Créer",
|
||||
|
||||
@@ -1849,6 +1849,7 @@
|
||||
"deleteSuccess": "プロバイダーを削除しました。",
|
||||
"deleteConfirmTitle": "プロバイダーを削除",
|
||||
"deleteConfirmMessage": "プロバイダー「{name}」を完全に削除しますか?",
|
||||
"deleteBlockedByAgent": "{agents} がこのプロバイダーを使用中です。削除する前にリンクを解除してください。",
|
||||
"cancel": "キャンセル",
|
||||
"delete": "削除",
|
||||
"create": "作成",
|
||||
|
||||
@@ -1849,6 +1849,7 @@
|
||||
"deleteSuccess": "제공업체가 삭제되었습니다.",
|
||||
"deleteConfirmTitle": "제공업체 삭제",
|
||||
"deleteConfirmMessage": "제공업체 \"{name}\"을(를) 영구적으로 삭제하시겠습니까?",
|
||||
"deleteBlockedByAgent": "{agents}이(가) 이 공급자를 사용 중입니다. 삭제하기 전에 연결을 해제해 주세요.",
|
||||
"cancel": "취소",
|
||||
"delete": "삭제",
|
||||
"create": "생성",
|
||||
|
||||
@@ -1849,6 +1849,7 @@
|
||||
"deleteSuccess": "Provedor excluído.",
|
||||
"deleteConfirmTitle": "Excluir Provedor",
|
||||
"deleteConfirmMessage": "O provedor \"{name}\" será excluído permanentemente. Tem certeza?",
|
||||
"deleteBlockedByAgent": "{agents} está usando este provedor. Desvincule-o antes de excluir.",
|
||||
"cancel": "Cancelar",
|
||||
"delete": "Excluir",
|
||||
"create": "Criar",
|
||||
|
||||
@@ -1849,6 +1849,7 @@
|
||||
"deleteSuccess": "供应商已删除。",
|
||||
"deleteConfirmTitle": "删除供应商",
|
||||
"deleteConfirmMessage": "确定要永久删除供应商「{name}」吗?",
|
||||
"deleteBlockedByAgent": "{agents} 正在使用该配置,请先解除关联后再删除。",
|
||||
"cancel": "取消",
|
||||
"delete": "删除",
|
||||
"create": "创建",
|
||||
|
||||
@@ -1849,6 +1849,7 @@
|
||||
"deleteSuccess": "供應商已刪除。",
|
||||
"deleteConfirmTitle": "刪除供應商",
|
||||
"deleteConfirmMessage": "確定要永久刪除供應商「{name}」嗎?",
|
||||
"deleteBlockedByAgent": "{agents} 正在使用此設定,請先解除關聯後再刪除。",
|
||||
"cancel": "取消",
|
||||
"delete": "刪除",
|
||||
"create": "建立",
|
||||
|
||||
Reference in New Issue
Block a user