| |
| |
| |
| |
| |
|
|
| 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; |
| } |
|
|
| |
| 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> |
| ); |
| } |
|
|