message / frontend /src /components /features /PluginCard.tsx
hunian
feat: 重构前端控制台和工具页面
a43ac26
Raw
History Blame Contribute Delete
3.07 kB
/**
* 插件卡片组件
*
* 使用 console 语义 token,与 PluginDetailPage 等页面保持一致
*/
import { Link } from 'react-router-dom';
import { Play, Pause, LayoutGrid } from 'lucide-react';
import { PluginListItem, PluginStatus } from '@typings/plugin';
import { StatusPill } from '@components/console';
import { Button } from '@components/ui/button';
interface PluginCardProps {
plugin: PluginListItem;
onEnable: (name: string) => void;
onDisable: (name: string) => void;
}
// 状态到 StatusPill 变体的映射
const statusVariantMap: Record<PluginStatus, 'enabled' | 'disabled' | 'error' | 'warning' | 'incomplete'> = {
enabled: 'enabled',
disabled: 'disabled',
error: 'error',
dependency_error: 'error',
incomplete: 'incomplete',
discovered: 'warning',
loaded: 'warning',
installed: 'disabled',
installing: 'warning',
uninstalling: 'warning',
};
export function PluginCard({ plugin, onEnable, onDisable }: PluginCardProps) {
const statusVariant = statusVariantMap[plugin.status] || 'disabled';
const hasUiPage = plugin.ui_entry?.type === 'static';
return (
<div className="py-3 px-4 bg-console-surface-raised rounded-console-md border border-console-border">
{/* 头部:名称 + 状态 */}
<div className="flex items-start justify-between gap-2">
<div className="min-w-0">
<h3 className="font-semibold text-console-text-primary truncate">
{plugin.metadata.name}
</h3>
<div className="flex items-center gap-1.5 mt-1 text-xs text-console-text-secondary">
<span>v{plugin.metadata.version}</span>
<span className="text-console-text-muted"></span>
<span>{plugin.metadata.author}</span>
</div>
</div>
<StatusPill status={statusVariant} />
</div>
{/* 描述 */}
<p className="text-sm text-console-text-secondary mt-3 line-clamp-2">
{plugin.metadata.description}
</p>
{plugin.errors.length > 0 && (
<p className="text-sm text-console-status-error mt-2">
{plugin.errors[0].message}
</p>
)}
{/* 操作按钮 */}
<div className="flex items-center gap-2 mt-3 pt-3 border-t border-console-border">
{plugin.status === 'disabled' && (
<Button size="sm" onClick={() => onEnable(plugin.metadata.name)} className="h-7 text-xs">
<Play className="h-3 w-3 mr-1" />
启用
</Button>
)}
{plugin.status === 'enabled' && (
<Button size="sm" variant="outline" onClick={() => onDisable(plugin.metadata.name)} className="h-7 text-xs">
<Pause className="h-3 w-3 mr-1" />
禁用
</Button>
)}
{hasUiPage && (
<Link to={`/tool/${plugin.metadata.name}`}>
<Button size="sm" variant="outline" className="h-7 text-xs">
<LayoutGrid className="h-3 w-3 mr-1" />
访问页面
</Button>
</Link>
)}
</div>
</div>
);
}