mirror of
https://github.com/musistudio/claude-code-router.git
synced 2026-01-30 06:12:06 +00:00
fix install preset error
This commit is contained in:
@@ -14,7 +14,7 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Upload, Link, Trash2, Info, Download, CheckCircle2, AlertCircle, Loader2, ArrowLeft, Store, Search, Package } from "lucide-react";
|
||||
import { Upload, Link, Trash2, Info, Download, Check, CheckCircle2, AlertCircle, Loader2, ArrowLeft, Store, Search, Package } from "lucide-react";
|
||||
import { Toast } from "@/components/ui/toast";
|
||||
import { DynamicConfigForm } from "./preset/DynamicConfigForm";
|
||||
|
||||
@@ -193,7 +193,13 @@ export function Presets() {
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Failed to install preset:', error);
|
||||
setToast({ message: t('presets.preset_install_failed', { error: error.message }), type: 'error' });
|
||||
// Check if it's an "already installed" error
|
||||
const errorMessage = error.message || '';
|
||||
if (errorMessage.includes('already installed') || errorMessage.includes('已安装')) {
|
||||
setToast({ message: t('presets.preset_already_installed'), type: 'warning' });
|
||||
} else {
|
||||
setToast({ message: t('presets.preset_install_failed', { error: errorMessage }), type: 'error' });
|
||||
}
|
||||
} finally {
|
||||
setInstallingFromMarket(null);
|
||||
}
|
||||
@@ -345,7 +351,13 @@ export function Presets() {
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Failed to install preset:', error);
|
||||
setToast({ message: t('presets.preset_install_failed', { error: error.message }), type: 'error' });
|
||||
// Check if it's an "already installed" error
|
||||
const errorMessage = error.message || '';
|
||||
if (errorMessage.includes('already installed') || errorMessage.includes('已安装')) {
|
||||
setToast({ message: t('presets.preset_already_installed'), type: 'warning' });
|
||||
} else {
|
||||
setToast({ message: t('presets.preset_install_failed', { error: errorMessage }), type: 'error' });
|
||||
}
|
||||
} finally {
|
||||
setIsInstalling(false);
|
||||
}
|
||||
@@ -636,56 +648,76 @@ export function Presets() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{filteredMarketPresets.map((preset) => (
|
||||
<div
|
||||
key={preset.id}
|
||||
className="p-4 border rounded-lg hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<h3 className="font-semibold text-lg">{preset.name}</h3>
|
||||
</div>
|
||||
{preset.description && (
|
||||
<p className="text-sm text-gray-600 mb-2">{preset.description}</p>
|
||||
)}
|
||||
<div className="flex items-center gap-4 text-sm text-gray-500">
|
||||
{preset.author && (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="font-medium">{t('presets.by', { author: preset.author })}</span>
|
||||
<a
|
||||
href={`https://github.com/${preset.repo}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-gray-600 hover:text-gray-900 transition-colors"
|
||||
title={t('presets.github_repository')}
|
||||
>
|
||||
<i className="ri-github-fill text-xl"></i>
|
||||
</a>
|
||||
</div>
|
||||
{filteredMarketPresets.map((preset) => {
|
||||
// Check if this preset is already installed by repo
|
||||
const isInstalled = presets.some(p => {
|
||||
// Extract repo from repository field (handle both formats)
|
||||
let installedRepo = '';
|
||||
if (p.repository) {
|
||||
// Remove GitHub URL prefix if present
|
||||
installedRepo = p.repository.replace(/^https:\/\/github\.com\//, '').replace(/\.git$/, '');
|
||||
}
|
||||
// Match by repo (preferred), or name as fallback
|
||||
return installedRepo === preset.repo || p.name === preset.name;
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
key={preset.id}
|
||||
className="p-4 border rounded-lg hover:bg-gray-50 transition-colors"
|
||||
>
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<h3 className="font-semibold text-lg">{preset.name}</h3>
|
||||
</div>
|
||||
{preset.description && (
|
||||
<p className="text-sm text-gray-600 mb-2">{preset.description}</p>
|
||||
)}
|
||||
<div className="flex items-center gap-4 text-sm text-gray-500">
|
||||
{preset.author && (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="font-medium">{t('presets.by', { author: preset.author })}</span>
|
||||
<a
|
||||
href={`https://github.com/${preset.repo}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-gray-600 hover:text-gray-900 transition-colors"
|
||||
title={t('presets.github_repository')}
|
||||
>
|
||||
<i className="ri-github-fill text-xl"></i>
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => handleInstallFromMarket(preset)}
|
||||
disabled={installingFromMarket === preset.id || isInstalled}
|
||||
variant={isInstalled ? "secondary" : "default"}
|
||||
className="shrink-0"
|
||||
>
|
||||
{installingFromMarket === preset.id ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
{t('presets.installing')}
|
||||
</>
|
||||
) : isInstalled ? (
|
||||
<>
|
||||
<Check className="mr-2 h-4 w-4" />
|
||||
{t('presets.installed_label')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
{t('presets.install')}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => handleInstallFromMarket(preset)}
|
||||
disabled={installingFromMarket === preset.id}
|
||||
className="shrink-0"
|
||||
>
|
||||
{installingFromMarket === preset.id ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
{t('presets.installing')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
{t('presets.install')}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -99,7 +99,17 @@ class ApiClient {
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API request failed: ${response.status} ${response.statusText}`);
|
||||
// Try to get detailed error message from response body
|
||||
let errorMessage = `API request failed: ${response.status} ${response.statusText}`;
|
||||
try {
|
||||
const errorData = await response.json();
|
||||
if (errorData.error || errorData.message) {
|
||||
errorMessage = errorData.message || errorData.error || errorMessage;
|
||||
}
|
||||
} catch {
|
||||
// If parsing fails, use default error message
|
||||
}
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
if (response.status === 204) {
|
||||
|
||||
@@ -255,6 +255,7 @@
|
||||
"view_details": "View Details",
|
||||
"install": "Install",
|
||||
"installing": "Installing...",
|
||||
"installed_label": "Installed",
|
||||
"apply": "Apply Preset",
|
||||
"applying": "Applying...",
|
||||
"close": "Close",
|
||||
@@ -274,6 +275,7 @@
|
||||
"delete_dialog_description": "Are you sure you want to delete preset \"{{name}}\"? This action cannot be undone.",
|
||||
"preset_installed": "Preset installed successfully",
|
||||
"preset_install_failed": "Failed to install preset: {{error}}",
|
||||
"preset_already_installed": "Preset already installed. Please delete it first if you want to reinstall.",
|
||||
"preset_applied": "Preset applied successfully",
|
||||
"preset_apply_failed": "Failed to apply preset: {{error}}",
|
||||
"preset_deleted": "Preset deleted successfully",
|
||||
|
||||
@@ -255,6 +255,7 @@
|
||||
"view_details": "查看详情",
|
||||
"install": "安装",
|
||||
"installing": "安装中...",
|
||||
"installed_label": "已安装",
|
||||
"apply": "应用预设",
|
||||
"applying": "应用中...",
|
||||
"close": "关闭",
|
||||
@@ -262,7 +263,6 @@
|
||||
"install_dialog_title": "安装预设",
|
||||
"install_dialog_description": "从 GitHub 仓库安装预设",
|
||||
"from_url": "从 GitHub",
|
||||
"github_repository": "GitHub 仓库",
|
||||
"preset_url": "仓库 URL",
|
||||
"preset_url_placeholder": "https://github.com/owner/repo",
|
||||
"preset_name": "预设名称 (可选)",
|
||||
@@ -274,6 +274,7 @@
|
||||
"delete_dialog_description": "您确定要删除预设 \"{{name}}\" 吗?此操作无法撤销。",
|
||||
"preset_installed": "预设安装成功",
|
||||
"preset_install_failed": "预设安装失败:{{error}}",
|
||||
"preset_already_installed": "预设已经安装。如需重新安装,请先删除现有预设。",
|
||||
"preset_applied": "预设应用成功",
|
||||
"preset_apply_failed": "预设应用失败:{{error}}",
|
||||
"preset_deleted": "预设删除成功",
|
||||
|
||||
Reference in New Issue
Block a user