import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import PluginForm from '@/app/home/plugins/components/plugin-installed/plugin-form/PluginForm'; import PluginReadme from '@/app/home/plugins/components/plugin-installed/plugin-readme/PluginReadme'; import PluginLogs from '@/app/home/plugins/components/plugin-installed/plugin-logs/PluginLogs'; import PluginComponentList from '@/app/home/plugins/components/plugin-installed/PluginComponentList'; import { useSidebarData } from '@/app/home/components/home-sidebar/SidebarDataContext'; import { useTranslation } from 'react-i18next'; import { Badge } from '@/components/ui/badge'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Button } from '@/components/ui/button'; import { Checkbox } from '@/components/ui/checkbox'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { httpClient } from '@/app/infra/http/HttpClient'; import { Plugin } from '@/app/infra/entities/plugin'; import { extractI18nObject } from '@/i18n/I18nProvider'; import { useAsyncTask, AsyncTaskStatus } from '@/hooks/useAsyncTask'; import { Bug, Puzzle, Trash2 } from 'lucide-react'; import { toast } from 'sonner'; /** * Plugin detail page content. * The `id` prop is the composite key "author/name". */ export default function PluginDetailContent({ id }: { id: string }) { const { t } = useTranslation(); const navigate = useNavigate(); const { plugins, setDetailEntityName, refreshPlugins } = useSidebarData(); const [pluginInfo, setPluginInfo] = useState(null); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [deleteData, setDeleteData] = useState(false); // Parse "author/name" composite key const slashIndex = id.indexOf('/'); const pluginAuthor = slashIndex >= 0 ? id.substring(0, slashIndex) : ''; const pluginName = slashIndex >= 0 ? id.substring(slashIndex + 1) : id; const plugin = plugins.find((p) => p.id === id); const title = pluginInfo?.manifest.manifest.metadata.label && extractI18nObject(pluginInfo.manifest.manifest.metadata.label) ? extractI18nObject(pluginInfo.manifest.manifest.metadata.label) : plugin?.name || `${pluginAuthor}/${pluginName}`; const description = pluginInfo?.manifest.manifest.metadata.description ? extractI18nObject(pluginInfo.manifest.manifest.metadata.description) : plugin?.description; const asyncTask = useAsyncTask({ onSuccess: () => { toast.success(t('plugins.deleteSuccess')); setShowDeleteConfirm(false); void refreshPlugins(); navigate('/home/extensions'); }, }); // Set breadcrumb entity name useEffect(() => { setDetailEntityName(plugin?.name ?? `${pluginAuthor}/${pluginName}`); return () => setDetailEntityName(null); }, [plugin, pluginAuthor, pluginName, setDetailEntityName]); useEffect(() => { let cancelled = false; httpClient.getPlugin(pluginAuthor, pluginName).then((res) => { if (!cancelled) { setPluginInfo(res.plugin); } }); return () => { cancelled = true; }; }, [pluginAuthor, pluginName]); function handleFormSubmit(timeout?: number) { if (timeout) { setTimeout(() => { refreshPlugins(); }, timeout); } else { refreshPlugins(); } } function executeDelete() { httpClient .removePlugin(pluginAuthor, pluginName, deleteData) .then((res) => { asyncTask.startTask(res.task_id); }) .catch((error) => { toast.error(t('plugins.deleteError') + error.message); }); } const sourceBadge = plugin?.debug ? ( {t('plugins.debugging')} ) : plugin?.installSource === 'github' ? ( {t('plugins.fromGithub')} ) : plugin?.installSource === 'local' ? ( {t('plugins.fromLocal')} ) : plugin?.installSource === 'marketplace' ? ( {t('plugins.fromMarketplace')} ) : null; const componentBadges = pluginInfo && ( >( (acc, component) => { const kind = component.manifest.manifest.kind; acc[kind] = (acc[kind] ?? 0) + 1; return acc; }, {}, )} showComponentName showTitle={false} useBadge t={t} /> ); const dangerZone = ( {t('plugins.dangerZone')} {t('plugins.dangerZoneDescription')}

{t('plugins.deletePlugin')}

{t('plugins.confirmDeletePlugin', { author: pluginAuthor, name: pluginName, })}

); return ( <>

{title}

{t('market.typePlugin')} {sourceBadge} {componentBadges}
{description && (

{description}

)}
{dangerZone}
{t('plugins.tabDocs')} {t('plugins.tabLogs')}
{t('plugins.deleteConfirm')} {asyncTask.status === AsyncTaskStatus.RUNNING ? t('plugins.deleting') : t('plugins.confirmDeletePlugin', { author: pluginAuthor, name: pluginName, })} {asyncTask.status === AsyncTaskStatus.WAIT_INPUT && (
setDeleteData(checked === true)} />
)} {asyncTask.status === AsyncTaskStatus.ERROR && (
{asyncTask.error}
)} {asyncTask.status === AsyncTaskStatus.WAIT_INPUT && ( )} {asyncTask.status === AsyncTaskStatus.WAIT_INPUT && ( )} {asyncTask.status === AsyncTaskStatus.RUNNING && ( )} {asyncTask.status === AsyncTaskStatus.ERROR && ( )}
); }