import React from 'react'; import { useTranslation } from 'react-i18next'; import { Progress } from '@/components/ui/progress'; import { Download, Package, CheckCircle2, XCircle, Loader2, X, ListTodo, Wrench, AudioWaveform, Book, } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Popover, PopoverContent, PopoverTrigger, } from '@/components/ui/popover'; import { Badge } from '@/components/ui/badge'; import { usePluginInstallTasks, InstallStage, PluginInstallTask, } from './PluginInstallTaskContext'; import { cn } from '@/lib/utils'; const STAGE_ICONS: Record = { [InstallStage.DOWNLOADING]: Download, [InstallStage.INSTALLING_DEPS]: Package, [InstallStage.DONE]: CheckCircle2, [InstallStage.ERROR]: XCircle, }; const EXTENSION_TYPE_ICONS: Record = { plugin: Wrench, mcp: AudioWaveform, skill: Book, }; function TaskQueueItem({ task, onClick, onRemove, }: { task: PluginInstallTask; onClick: () => void; onRemove: () => void; }) { const { t } = useTranslation(); const isDone = task.stage === InstallStage.DONE; const isError = task.stage === InstallStage.ERROR; const isRunning = !isDone && !isError; const StageIcon = STAGE_ICONS[task.stage] || Download; const TypeIcon = EXTENSION_TYPE_ICONS[task.extensionType] || Wrench; const getTypeBadgeClass = () => { switch (task.extensionType) { case 'mcp': return 'border-sky-500 text-sky-600 dark:border-sky-400 dark:text-sky-300'; case 'skill': return 'border-emerald-500 text-emerald-600 dark:border-emerald-400 dark:text-emerald-300'; default: return 'border-violet-500 text-violet-600 dark:border-violet-400 dark:text-violet-300'; } }; const getTypeLabel = () => { switch (task.extensionType) { case 'mcp': return 'MCP'; case 'skill': return t('common.skill'); default: return t('market.typePlugin'); } }; const getInstallCompleteMessage = () => { switch (task.extensionType) { case 'mcp': return t('plugins.installProgress.installCompleteMCP'); case 'skill': return t('plugins.installProgress.installCompleteSkill'); default: return t('plugins.installProgress.installCompletePlugin'); } }; const stageLabel = (() => { switch (task.stage) { case InstallStage.DOWNLOADING: return t('plugins.installProgress.downloading'); case InstallStage.INSTALLING_DEPS: return t('plugins.installProgress.installingDeps'); case InstallStage.DONE: return isDone ? getInstallCompleteMessage() : t('plugins.installProgress.completed'); case InstallStage.ERROR: return t('plugins.installProgress.failed'); default: return ''; } })(); return (
{isRunning ? ( ) : ( )}
{task.pluginName}
{getTypeLabel()}
{stageLabel} {isRunning && ( {task.overallProgress}% )}
{isRunning && ( )}
{(isDone || isError) && ( )}
); } export default function PluginInstallTaskQueue() { const { t } = useTranslation(); const { tasks, setSelectedTaskId, removeTask, clearCompletedTasks } = usePluginInstallTasks(); const runningCount = tasks.filter( (t) => t.stage !== InstallStage.DONE && t.stage !== InstallStage.ERROR, ).length; const hasCompleted = tasks.some( (t) => t.stage === InstallStage.DONE || t.stage === InstallStage.ERROR, ); return (
{t('plugins.installProgress.taskQueue')} {hasCompleted && ( )}
{tasks.length === 0 ? (
{t('plugins.installProgress.noTasks')}
) : ( tasks.map((task) => ( setSelectedTaskId(task.id)} onRemove={() => removeTask(task.id)} /> )) )}
); }