()
| 17 | import { PresetsManager } from "@/components/presets-manager"; |
| 18 | |
| 19 | export default function PluginsPage() { |
| 20 | const { plugins, loading, refreshData, togglePlugin } = useApp(); |
| 21 | const router = useRouter(); |
| 22 | const [search, setSearch] = useState(""); |
| 23 | const [activeGPlugin, setActiveGPlugin] = useState<string | null>(null); |
| 24 | |
| 25 | useEffect(() => { |
| 26 | getActiveGooglePlugin().then(res => setActiveGPlugin(res.activePlugin)).catch(() => {}); |
| 27 | }, []); |
| 28 | |
| 29 | const filteredPlugins = useMemo(() => { |
| 30 | if (!search.trim()) return plugins; |
| 31 | const q = search.toLowerCase(); |
| 32 | return plugins.filter(p => p.name.toLowerCase().includes(q)); |
| 33 | }, [plugins, search]); |
| 34 | |
| 35 | const handleOpen = (name: string, type: 'file' | 'npm') => { |
| 36 | if (type === 'npm') return; |
| 37 | router.push(`/editor?type=plugins&name=${encodeURIComponent(name)}`); |
| 38 | }; |
| 39 | |
| 40 | const handleToggle = async (name: string) => { |
| 41 | try { |
| 42 | await togglePlugin(name); |
| 43 | const plugin = plugins.find(p => p.name === name); |
| 44 | toast.success(`${name} ${plugin?.enabled ? "disabled" : "enabled"}`); |
| 45 | } catch (err: any) { |
| 46 | const msg = err.response?.data?.error || err.message || "Unknown error"; |
| 47 | toast.error(`Failed to toggle plugin: ${msg}`); |
| 48 | } |
| 49 | }; |
| 50 | |
| 51 | const handleDelete = async (name: string, type: 'file' | 'npm') => { |
| 52 | if (!confirm(`Delete ${name}?`)) return; |
| 53 | try { |
| 54 | if (type === 'npm') { |
| 55 | await deletePluginFromConfig(name); |
| 56 | } else { |
| 57 | await deletePlugin(name); |
| 58 | } |
| 59 | toast.success(`${name} deleted`); |
| 60 | refreshData(); |
| 61 | } catch (err: any) { |
| 62 | const msg = err.response?.data?.error || err.message || "Unknown error"; |
| 63 | toast.error(`Failed to delete plugin: ${msg}`); |
| 64 | } |
| 65 | }; |
| 66 | |
| 67 | if (loading) { |
| 68 | return ( |
| 69 | <div className="space-y-4"> |
| 70 | <div className="flex justify-between items-center"> |
| 71 | <PageHelp title="Plugins" docUrl="https://opencode.ai/docs/plugins" docTitle="Plugins Documentation" /> |
| 72 | </div> |
| 73 | <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"> |
| 74 | {[1, 2, 3, 4].map((i) => ( |
| 75 | <Skeleton key={i} className="h-16" /> |
| 76 | ))} |
nothing calls this directly
no test coverage detected