import { useEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { invoke } from '@tauri-apps/api/core'; import { ExternalLink, X } from 'lucide-react'; import { useDialogFocusTrap } from '../components/useDialogFocusTrap'; import { useI18n } from '../i18n'; import { pluginText } from '../i18n/plugins'; import { pluginStoreApi, type PluginStoreEntry, type PluginStoreInstallResult } from '../services/plugins'; import { buildRepositoryURL } from '../services/pluginResources'; import { isValidManualReleaseTag, supportsPluginVersionSelection } from '../services/pluginReleaseVersions'; export function PluginInstallDialog({ entry, onClose, onInstalled }: { entry: PluginStoreEntry; onClose: () => void; onInstalled: (result: PluginStoreInstallResult) => void; }) { const { t, locale } = useI18n(); const pt = (key: Parameters[0]) => pluginText(key, locale); const [version, setVersion] = useState(''); const [busy, setBusy] = useState(false); const [error, setError] = useState(''); const pending = useRef(false); const mounted = useRef(true); useEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []); // The dialog remains open throughout installation, including on errors. const ref = useDialogFocusTrap({ onEscape: busy ? undefined : onClose, preventEscape: busy }); const canSelectVersion = supportsPluginVersionSelection(entry.installType); const validVersion = !version.trim() || isValidManualReleaseTag(version); const repository = buildRepositoryURL(entry.repository); const action = entry.installed ? pt('update') : pt('install'); const install = async () => { if (pending.current || !validVersion) return; pending.current = true; setBusy(true); setError(''); try { const result = await pluginStoreApi.install(entry.id, { sourceId: entry.sourceId, version: canSelectVersion ? version.trim() : undefined }); if (mounted.current) onInstalled(result); } catch (reason) { if (mounted.current) setError(reason instanceof Error ? reason.message : String(reason)); } finally { pending.current = false; if (mounted.current) setBusy(false); } }; return createPortal(

{action} · {entry.name || entry.id}

{pt('source')}
{entry.sourceName || entry.sourceId}{entry.sourceUrl}
{pt('repository')}
{entry.repository || '—'}{repository && }
{canSelectVersion && } {error &&

{error}

}
, document.body); }