import { PluginCardVO } from '@/app/home/plugins/components/plugin-installed/PluginCardVO';
import { useState } from 'react';
import { Badge } from '@/components/ui/badge';
import { useTranslation } from 'react-i18next';
import {
BugIcon,
ExternalLink,
Ellipsis,
Trash,
ArrowUp,
Puzzle,
} from 'lucide-react';
import { getCloudServiceClientSync, systemInfo } from '@/app/infra/http';
import { useInstalledPluginIcon } from '@/app/infra/hooks/useInstalledPluginIcon';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import PluginComponentList from '@/app/home/plugins/components/plugin-installed/PluginComponentList';
export default function PluginCardComponent({
cardVO,
onCardClick,
onDeleteClick,
onUpgradeClick,
}: {
cardVO: PluginCardVO;
onCardClick: () => void;
onDeleteClick: (cardVO: PluginCardVO) => void;
onUpgradeClick: (cardVO: PluginCardVO) => void;
}) {
const { t } = useTranslation();
const [dropdownOpen, setDropdownOpen] = useState(false);
const iconURL = useInstalledPluginIcon(cardVO.author, cardVO.name);
return (
<>
onCardClick()}
>
{/* Icon - fixed width */}
{iconURL ? (

) : (
)}
{/* Content area - flexible width with min-width to prevent overflow */}
{/* Top content area - allows overflow with max height */}
{cardVO.author} / {cardVO.name}
{cardVO.label}
v{cardVO.version}
{cardVO.type && (
{cardVO.type === 'mcp'
? 'MCP'
: cardVO.type === 'skill'
? t('common.skill')
: t('market.typePlugin')}
)}
{cardVO.debug && (
{t('plugins.debugging')}
)}
{!cardVO.debug && (
<>
{cardVO.install_source === 'github' && (
{t('plugins.fromGithub')}
)}
{cardVO.install_source === 'local' && (
{t('plugins.fromLocal')}
)}
{cardVO.install_source === 'marketplace' && (
{t('plugins.fromMarketplace')}
)}
>
)}
{cardVO.description}
{/* Components list - fixed at bottom */}
{
const componentKindCount: Record = {};
for (const component of cardVO.components) {
const kind = component.manifest.manifest.kind;
if (componentKindCount[kind]) {
componentKindCount[kind]++;
} else {
componentKindCount[kind] = 1;
}
}
return componentKindCount;
})()}
showComponentName={false}
showTitle={true}
useBadge={false}
t={t}
/>
{/* Menu button - fixed width and position */}
e.stopPropagation()}
>
{
setDropdownOpen(open);
}}
>
{cardVO.hasUpdate && (
)}
{/**upgrade */}
{cardVO.install_source === 'marketplace' && (
{
e.stopPropagation();
onUpgradeClick(cardVO);
setDropdownOpen(false);
}}
>
{t('plugins.update')}
{cardVO.hasUpdate && (
{t('plugins.new')}
)}
)}
{/**view source */}
{(cardVO.install_source === 'github' ||
cardVO.install_source === 'marketplace') && (
{
e.stopPropagation();
if (cardVO.install_source === 'github') {
window.open(cardVO.install_info.github_url, '_blank');
} else if (cardVO.install_source === 'marketplace') {
window.open(
getCloudServiceClientSync().getPluginMarketplaceURL(
systemInfo.cloud_service_url,
cardVO.author,
cardVO.name,
),
'_blank',
);
}
setDropdownOpen(false);
}}
>
{t('plugins.viewSource')}
)}
{
e.stopPropagation();
onDeleteClick(cardVO);
setDropdownOpen(false);
}}
>
{t('plugins.delete')}
>
);
}