chore: remove ccw-litellm UI components (dead code)

The LiteLLM Python bridge was already removed (litellm-client.ts is a
stub). Remove the orphaned frontend components:
- CcwLitellmStatus component and LitellmInstallProgressOverlay
- API functions (checkCcwLitellmStatus, installCcwLitellm, uninstallCcwLitellm)
- React Query hooks (useCcwLitellmStatus, useInstallCcwLitellm, useUninstallCcwLitellm)
- Locale entries (zh/en api-settings.json ccwLitellm section)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
catlog22
2026-03-19 20:24:45 +08:00
parent 28e9701fe1
commit e1c7192509
8 changed files with 1 additions and 647 deletions

View File

@@ -1,178 +0,0 @@
// ========================================
// CCW-LiteLLM Status & Install Component
// ========================================
// Shows ccw-litellm installation status with install/uninstall actions
import { useState } from 'react';
import { useIntl } from 'react-intl';
import {
Download,
Trash2,
RefreshCw,
CheckCircle2,
XCircle,
Loader2,
Package,
AlertTriangle,
} from 'lucide-react';
import { Button } from '@/components/ui/Button';
import { Card, CardContent } from '@/components/ui/Card';
import { Badge } from '@/components/ui/Badge';
import {
useCcwLitellmStatus,
useInstallCcwLitellm,
useUninstallCcwLitellm,
} from '@/hooks/useApiSettings';
import { useNotifications } from '@/hooks/useNotifications';
import { LitellmInstallProgressOverlay } from './LitellmInstallProgressOverlay';
export function CcwLitellmStatus() {
const { formatMessage } = useIntl();
const { success, error: notifyError } = useNotifications();
const [refresh, setRefresh] = useState(false);
const [isInstallOverlayOpen, setIsInstallOverlayOpen] = useState(false);
const { data: status, isLoading, refetch } = useCcwLitellmStatus({ refresh });
const { install, isInstalling } = useInstallCcwLitellm();
const { uninstall, isUninstalling } = useUninstallCcwLitellm();
const isBusy = isInstalling || isUninstalling;
const handleInstallViaOverlay = async (): Promise<{ success: boolean }> => {
try {
await install();
success(formatMessage({ id: 'apiSettings.ccwLitellm.messages.installSuccess' }));
return { success: true };
} catch {
notifyError(formatMessage({ id: 'apiSettings.ccwLitellm.messages.installFailed' }));
return { success: false };
}
};
const handleInstallSuccess = () => {
setRefresh(true);
refetch();
};
const handleUninstall = async () => {
try {
await uninstall();
success(formatMessage({ id: 'apiSettings.ccwLitellm.messages.uninstallSuccess' }));
setRefresh(true);
refetch();
} catch {
notifyError(formatMessage({ id: 'apiSettings.ccwLitellm.messages.uninstallFailed' }));
}
};
const handleRefresh = () => {
setRefresh(true);
refetch();
};
const installed = status?.installed ?? false;
const version = status?.version;
const systemPythonInstalled = status?.checks?.systemPython?.installed === true;
const showSystemPythonMismatch = !isLoading && !installed && systemPythonInstalled;
return (
<>
<Card>
<CardContent className="p-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Package className="w-5 h-5 text-primary" />
<div>
<h3 className="text-sm font-medium">
{formatMessage({ id: 'apiSettings.ccwLitellm.title' })}
</h3>
<p className="text-xs text-muted-foreground">
{formatMessage({ id: 'apiSettings.ccwLitellm.description' })}
</p>
{showSystemPythonMismatch && (
<div className="mt-1 flex items-start gap-2 text-xs text-warning-foreground/80">
<AlertTriangle className="w-4 h-4 text-warning flex-shrink-0 mt-0.5" />
<p>{formatMessage({ id: 'apiSettings.ccwLitellm.systemPythonMismatch' })}</p>
</div>
)}
</div>
</div>
<div className="flex items-center gap-2">
{/* Status badge */}
{isLoading ? (
<Badge variant="secondary" className="gap-1">
<Loader2 className="w-3 h-3 animate-spin" />
...
</Badge>
) : installed ? (
<Badge variant="default" className="gap-1">
<CheckCircle2 className="w-3 h-3" />
{formatMessage({ id: 'apiSettings.ccwLitellm.status.installed' })}
{version && ` v${version}`}
</Badge>
) : (
<Badge variant="destructive" className="gap-1">
<XCircle className="w-3 h-3" />
{formatMessage({ id: 'apiSettings.ccwLitellm.status.notInstalled' })}
</Badge>
)}
{/* Refresh */}
<Button
variant="ghost"
size="sm"
onClick={handleRefresh}
disabled={isBusy || isLoading}
aria-label={formatMessage({ id: 'apiSettings.ccwLitellm.actions.refreshStatus' })}
>
<RefreshCw className={`w-4 h-4 ${isLoading ? 'animate-spin' : ''}`} />
</Button>
{/* Install / Uninstall */}
{installed ? (
<Button
variant="outline"
size="sm"
onClick={handleUninstall}
disabled={isBusy}
>
{isUninstalling ? (
<Loader2 className="w-4 h-4 mr-1 animate-spin" />
) : (
<Trash2 className="w-4 h-4 mr-1" />
)}
{formatMessage({ id: 'apiSettings.ccwLitellm.actions.uninstall' })}
</Button>
) : (
<Button
variant="default"
size="sm"
onClick={() => setIsInstallOverlayOpen(true)}
disabled={isBusy}
>
{isInstalling ? (
<Loader2 className="w-4 h-4 mr-1 animate-spin" />
) : (
<Download className="w-4 h-4 mr-1" />
)}
{formatMessage({ id: 'apiSettings.ccwLitellm.actions.install' })}
</Button>
)}
</div>
</div>
</CardContent>
</Card>
{/* Install Progress Overlay */}
<LitellmInstallProgressOverlay
open={isInstallOverlayOpen}
onOpenChange={setIsInstallOverlayOpen}
onInstall={handleInstallViaOverlay}
onSuccess={handleInstallSuccess}
/>
</>
);
}
export default CcwLitellmStatus;

View File

@@ -1,267 +0,0 @@
// ========================================
// CCW-LiteLLM Install Progress Overlay
// ========================================
// Dialog overlay showing staged progress during ccw-litellm installation
// Adapted from CodexLens InstallProgressOverlay pattern
import { useState, useEffect, useRef, useCallback } from 'react';
import { useIntl } from 'react-intl';
import {
Check,
Download,
Info,
Loader2,
} from 'lucide-react';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/Dialog';
import { Button } from '@/components/ui/Button';
import { Progress } from '@/components/ui/Progress';
import { Card, CardContent } from '@/components/ui/Card';
// ----------------------------------------
// Types
// ----------------------------------------
interface InstallStage {
progress: number;
messageId: string;
}
interface LitellmInstallProgressOverlayProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onInstall: () => Promise<{ success: boolean }>;
onSuccess?: () => void;
}
// ----------------------------------------
// Constants
// ----------------------------------------
const INSTALL_STAGES: InstallStage[] = [
{ progress: 10, messageId: 'apiSettings.ccwLitellm.install.stage.checkingVenv' },
{ progress: 25, messageId: 'apiSettings.ccwLitellm.install.stage.detectingPackage' },
{ progress: 45, messageId: 'apiSettings.ccwLitellm.install.stage.installingDeps' },
{ progress: 65, messageId: 'apiSettings.ccwLitellm.install.stage.installingPackage' },
{ progress: 85, messageId: 'apiSettings.ccwLitellm.install.stage.verifying' },
];
const STAGE_INTERVAL_MS = 2000;
// ----------------------------------------
// Checklist items
// ----------------------------------------
interface ChecklistItem {
labelId: string;
descId: string;
}
const CHECKLIST_ITEMS: ChecklistItem[] = [
{ labelId: 'apiSettings.ccwLitellm.install.codexlensVenv', descId: 'apiSettings.ccwLitellm.install.codexlensVenvDesc' },
{ labelId: 'apiSettings.ccwLitellm.install.litellmPackage', descId: 'apiSettings.ccwLitellm.install.litellmPackageDesc' },
{ labelId: 'apiSettings.ccwLitellm.install.embeddingSupport', descId: 'apiSettings.ccwLitellm.install.embeddingSupportDesc' },
];
// ----------------------------------------
// Component
// ----------------------------------------
export function LitellmInstallProgressOverlay({
open,
onOpenChange,
onInstall,
onSuccess,
}: LitellmInstallProgressOverlayProps) {
const { formatMessage } = useIntl();
const [isInstalling, setIsInstalling] = useState(false);
const [progress, setProgress] = useState(0);
const [stageText, setStageText] = useState('');
const [isComplete, setIsComplete] = useState(false);
const [errorText, setErrorText] = useState('');
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
const clearStageInterval = useCallback(() => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
}, []);
// Reset state when dialog closes
useEffect(() => {
if (!open) {
setIsInstalling(false);
setProgress(0);
setStageText('');
setIsComplete(false);
setErrorText('');
clearStageInterval();
}
}, [open, clearStageInterval]);
// Cleanup on unmount
useEffect(() => {
return () => clearStageInterval();
}, [clearStageInterval]);
const handleInstall = async () => {
setIsInstalling(true);
setProgress(0);
setIsComplete(false);
setErrorText('');
// Start stage simulation
let currentStage = 0;
setStageText(formatMessage({ id: INSTALL_STAGES[0].messageId }));
setProgress(INSTALL_STAGES[0].progress);
currentStage = 1;
intervalRef.current = setInterval(() => {
if (currentStage < INSTALL_STAGES.length) {
setStageText(formatMessage({ id: INSTALL_STAGES[currentStage].messageId }));
setProgress(INSTALL_STAGES[currentStage].progress);
currentStage++;
}
}, STAGE_INTERVAL_MS);
try {
const result = await onInstall();
clearStageInterval();
if (result.success) {
setProgress(100);
setStageText(formatMessage({ id: 'apiSettings.ccwLitellm.install.stage.complete' }));
setIsComplete(true);
// Auto-close after showing completion
setTimeout(() => {
onOpenChange(false);
onSuccess?.();
}, 1200);
} else {
setIsInstalling(false);
setProgress(0);
setStageText('');
setErrorText(formatMessage({ id: 'apiSettings.ccwLitellm.messages.installFailed' }));
}
} catch {
clearStageInterval();
setIsInstalling(false);
setProgress(0);
setStageText('');
setErrorText(formatMessage({ id: 'apiSettings.ccwLitellm.messages.installFailed' }));
}
};
return (
<Dialog open={open} onOpenChange={isInstalling ? undefined : onOpenChange}>
<DialogContent className="max-w-lg" onPointerDownOutside={isInstalling ? (e) => e.preventDefault() : undefined}>
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Download className="w-5 h-5 text-primary" />
{formatMessage({ id: 'apiSettings.ccwLitellm.install.title' })}
</DialogTitle>
<DialogDescription>
{formatMessage({ id: 'apiSettings.ccwLitellm.install.description' })}
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
{/* Install Checklist */}
<div>
<h4 className="text-sm font-medium mb-2">
{formatMessage({ id: 'apiSettings.ccwLitellm.install.checklist' })}
</h4>
<ul className="space-y-2">
{CHECKLIST_ITEMS.map((item) => (
<li key={item.labelId} className="flex items-start gap-2 text-sm">
<Check className="w-4 h-4 text-green-500 mt-0.5 flex-shrink-0" />
<span>
<strong>{formatMessage({ id: item.labelId })}</strong>
{' - '}
{formatMessage({ id: item.descId })}
</span>
</li>
))}
</ul>
</div>
{/* Install Info */}
<Card className="bg-primary/5 border-primary/20">
<CardContent className="p-3 flex items-start gap-2">
<Info className="w-4 h-4 text-primary mt-0.5 flex-shrink-0" />
<div className="text-sm text-muted-foreground">
<p className="font-medium text-foreground">
{formatMessage({ id: 'apiSettings.ccwLitellm.install.location' })}
</p>
<p className="mt-1">
<code className="bg-muted px-1.5 py-0.5 rounded text-xs">
{formatMessage({ id: 'apiSettings.ccwLitellm.install.locationPath' })}
</code>
</p>
<p className="mt-1">
{formatMessage({ id: 'apiSettings.ccwLitellm.install.timeEstimate' })}
</p>
</div>
</CardContent>
</Card>
{/* Progress Section - shown during install */}
{isInstalling && (
<div className="space-y-2">
<div className="flex items-center gap-3">
{isComplete ? (
<Check className="w-5 h-5 text-green-500" />
) : (
<Loader2 className="w-5 h-5 text-primary animate-spin" />
)}
<span className="text-sm">{stageText}</span>
</div>
<Progress value={progress} className="h-2" />
</div>
)}
{/* Error message */}
{errorText && !isInstalling && (
<p className="text-sm text-destructive">{errorText}</p>
)}
</div>
<DialogFooter>
<Button
variant="outline"
onClick={() => onOpenChange(false)}
disabled={isInstalling}
>
{formatMessage({ id: 'apiSettings.common.cancel' })}
</Button>
<Button
onClick={handleInstall}
disabled={isInstalling}
>
{isInstalling ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
{formatMessage({ id: 'apiSettings.ccwLitellm.install.installing' })}
</>
) : (
<>
<Download className="w-4 h-4 mr-2" />
{formatMessage({ id: 'apiSettings.ccwLitellm.install.installNow' })}
</>
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
export default LitellmInstallProgressOverlay;

View File

@@ -13,4 +13,4 @@ export { CliSettingsList } from './CliSettingsList';
export { CliSettingsModal } from './CliSettingsModal';
export { MultiKeySettingsModal } from './MultiKeySettingsModal';
export { ManageModelsModal } from './ManageModelsModal';
export { CcwLitellmStatus } from './CcwLitellmStatus';

View File

@@ -33,9 +33,6 @@ import {
fetchApiConfig,
syncApiConfig,
previewYamlConfig,
checkCcwLitellmStatus,
installCcwLitellm,
uninstallCcwLitellm,
fetchCliSettings,
createCliSettings,
updateCliSettings,
@@ -60,7 +57,6 @@ export const apiSettingsKeys = {
cache: () => [...apiSettingsKeys.all, 'cache'] as const,
modelPools: () => [...apiSettingsKeys.all, 'modelPools'] as const,
modelPool: (id: string) => [...apiSettingsKeys.modelPools(), id] as const,
ccwLitellm: () => [...apiSettingsKeys.all, 'ccwLitellm'] as const,
cliSettings: () => [...apiSettingsKeys.all, 'cliSettings'] as const,
cliSetting: (id: string) => [...apiSettingsKeys.cliSettings(), id] as const,
};
@@ -631,61 +627,6 @@ export function usePreviewYamlConfig() {
});
}
// ========================================
// CCW-LiteLLM Package Hooks
// ========================================
export interface UseCcwLitellmStatusOptions {
staleTime?: number;
enabled?: boolean;
refresh?: boolean;
}
export function useCcwLitellmStatus(options: UseCcwLitellmStatusOptions = {}) {
const { staleTime = 5 * 60 * 1000, enabled = true, refresh = false } = options;
return useQuery({
queryKey: [...apiSettingsKeys.ccwLitellm(), 'status', refresh],
queryFn: () => checkCcwLitellmStatus(refresh),
staleTime,
enabled,
});
}
export function useInstallCcwLitellm() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: () => installCcwLitellm(),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: apiSettingsKeys.ccwLitellm() });
},
});
return {
install: mutation.mutateAsync,
isInstalling: mutation.isPending,
error: mutation.error,
};
}
export function useUninstallCcwLitellm() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: () => uninstallCcwLitellm(),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: apiSettingsKeys.ccwLitellm() });
},
});
return {
uninstall: mutation.mutateAsync,
isUninstalling: mutation.isPending,
error: mutation.error,
};
}
// ========================================
// CLI Settings Hooks
// ========================================

View File

@@ -5636,54 +5636,6 @@ export async function previewYamlConfig(): Promise<{ success: boolean; config: s
return fetchApi('/api/litellm-api/config/yaml-preview');
}
// ========== CCW-LiteLLM Package Management ==========
export interface CcwLitellmEnvCheck {
python: string;
installed: boolean;
version?: string;
error?: string;
}
export interface CcwLitellmStatus {
/**
* Whether ccw-litellm is installed in the CodexLens venv.
* This is the environment used for the LiteLLM embedding backend.
*/
installed: boolean;
version?: string;
error?: string;
checks?: {
codexLensVenv: CcwLitellmEnvCheck;
systemPython?: CcwLitellmEnvCheck;
};
}
/**
* Check ccw-litellm status
*/
export async function checkCcwLitellmStatus(refresh = false): Promise<CcwLitellmStatus> {
return fetchApi(`/api/litellm-api/ccw-litellm/status${refresh ? '?refresh=true' : ''}`);
}
/**
* Install ccw-litellm
*/
export async function installCcwLitellm(): Promise<{ success: boolean; message?: string; error?: string; path?: string }> {
return fetchApi('/api/litellm-api/ccw-litellm/install', {
method: 'POST',
});
}
/**
* Uninstall ccw-litellm
*/
export async function uninstallCcwLitellm(): Promise<{ success: boolean; message?: string; error?: string }> {
return fetchApi('/api/litellm-api/ccw-litellm/uninstall', {
method: 'POST',
});
}
// ========== CLI Settings Management ==========
/**

View File

@@ -319,51 +319,6 @@
"deleteError": "Failed to delete CLI settings",
"toggleError": "Failed to toggle CLI settings"
},
"ccwLitellm": {
"title": "CCW-LiteLLM Package",
"description": "Manage ccw-litellm Python package installation",
"systemPythonMismatch": "Detected ccw-litellm installed in system Python, but not in the CodexLens venv (~/.codexlens/venv). Click Install to install it into the venv.",
"status": {
"installed": "Installed",
"notInstalled": "Not Installed",
"version": "Version"
},
"actions": {
"install": "Install",
"uninstall": "Uninstall",
"refreshStatus": "Refresh Status"
},
"messages": {
"installSuccess": "ccw-litellm installed successfully",
"installFailed": "Failed to install ccw-litellm",
"uninstallSuccess": "ccw-litellm uninstalled successfully",
"uninstallFailed": "Failed to uninstall ccw-litellm"
},
"install": {
"title": "Install CCW-LiteLLM",
"description": "Install ccw-litellm into the CodexLens Python virtual environment for embedding support.",
"checklist": "What will be installed",
"codexlensVenv": "CodexLens Venv",
"codexlensVenvDesc": "Ensures CodexLens Python virtual environment is ready",
"litellmPackage": "ccw-litellm Package",
"litellmPackageDesc": "LiteLLM-based embedding client for multi-provider support",
"embeddingSupport": "Embedding Support",
"embeddingSupportDesc": "Enables LiteLLM embedding backend for semantic search",
"location": "Install Location",
"locationPath": "~/.codexlens/venv",
"timeEstimate": "Installation may take 1-3 minutes depending on network speed.",
"installNow": "Install Now",
"installing": "Installing...",
"stage": {
"checkingVenv": "Checking CodexLens virtual environment...",
"detectingPackage": "Detecting ccw-litellm package source...",
"installingDeps": "Installing dependencies...",
"installingPackage": "Installing ccw-litellm package...",
"verifying": "Verifying installation...",
"complete": "Installation complete!"
}
}
},
"common": {
"save": "Save",
"cancel": "Cancel",

View File

@@ -319,51 +319,6 @@
"deleteError": "删除 CLI 设置失败",
"toggleError": "切换 CLI 设置状态失败"
},
"ccwLitellm": {
"title": "CCW-LiteLLM 包",
"description": "管理 ccw-litellm Python 包安装",
"systemPythonMismatch": "检测到 ccw-litellm 已安装在系统 Python 中,但未安装到 CodexLens 虚拟环境(~/.codexlens/venv所以这里显示未安装。点击“安装”即可安装到虚拟环境中。",
"status": {
"installed": "已安装",
"notInstalled": "未安装",
"version": "版本"
},
"actions": {
"install": "安装",
"uninstall": "卸载",
"refreshStatus": "刷新状态"
},
"messages": {
"installSuccess": "ccw-litellm 安装成功",
"installFailed": "ccw-litellm 安装失败",
"uninstallSuccess": "ccw-litellm 卸载成功",
"uninstallFailed": "ccw-litellm 卸载失败"
},
"install": {
"title": "安装 CCW-LiteLLM",
"description": "将 ccw-litellm 安装到 CodexLens Python 虚拟环境中以支持嵌入功能。",
"checklist": "将要安装的内容",
"codexlensVenv": "CodexLens 虚拟环境",
"codexlensVenvDesc": "确保 CodexLens Python 虚拟环境就绪",
"litellmPackage": "ccw-litellm 包",
"litellmPackageDesc": "基于 LiteLLM 的嵌入客户端,支持多提供商",
"embeddingSupport": "嵌入支持",
"embeddingSupportDesc": "启用 LiteLLM 嵌入后端用于语义搜索",
"location": "安装位置",
"locationPath": "~/.codexlens/venv",
"timeEstimate": "安装可能需要 1-3 分钟,取决于网络速度。",
"installNow": "立即安装",
"installing": "安装中...",
"stage": {
"checkingVenv": "正在检查 CodexLens 虚拟环境...",
"detectingPackage": "正在检测 ccw-litellm 包来源...",
"installingDeps": "正在安装依赖项...",
"installingPackage": "正在安装 ccw-litellm 包...",
"verifying": "正在验证安装...",
"complete": "安装完成!"
}
}
},
"common": {
"save": "保存",
"cancel": "取消",

View File

@@ -23,7 +23,6 @@ import {
CliSettingsModal,
MultiKeySettingsModal,
ManageModelsModal,
CcwLitellmStatus,
} from '@/components/api-settings';
import { useProviders, useEndpoints, useModelPools, useCliSettings, useSyncApiConfig } from '@/hooks/useApiSettings';
import { useNotifications } from '@/hooks/useNotifications';
@@ -208,9 +207,6 @@ export function ApiSettingsPage() {
</Button>
</div>
{/* CCW-LiteLLM Status */}
<CcwLitellmStatus />
{/* Tabbed Interface */}
<TabsNavigation
value={activeTab}