Barazo default frontend barazo.forum
at main 71 lines 1.9 kB view raw
1'use client' 2 3import { Component, type ReactNode, type ComponentType } from 'react' 4import { usePlugins } from '@/hooks/use-plugins' 5import { getPluginComponents, type SlotName } from '@/lib/plugins/registry' 6 7interface PluginSlotProps { 8 name: SlotName 9 context?: Record<string, unknown> 10 fallback?: ReactNode 11} 12 13// Error boundary for individual plugin components 14interface ErrorBoundaryProps { 15 pluginName: string 16 children: ReactNode 17} 18 19interface ErrorBoundaryState { 20 hasError: boolean 21} 22 23class PluginErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> { 24 constructor(props: ErrorBoundaryProps) { 25 super(props) 26 this.state = { hasError: false } 27 } 28 29 static getDerivedStateFromError(): ErrorBoundaryState { 30 return { hasError: true } 31 } 32 33 render() { 34 if (this.state.hasError) { 35 return ( 36 <div className="rounded border border-destructive/20 bg-destructive/5 px-3 py-2 text-xs text-destructive"> 37 Plugin &ldquo;{this.props.pluginName}&rdquo; encountered an error. 38 </div> 39 ) 40 } 41 return this.props.children 42 } 43} 44 45export function PluginSlot({ name, context = {}, fallback }: PluginSlotProps) { 46 const { plugins } = usePlugins() 47 48 const registrations = getPluginComponents(name) 49 50 // Filter to only enabled plugins 51 const activeRegistrations = registrations.filter((reg) => 52 plugins.some((p) => p.name === reg.pluginName && p.enabled) 53 ) 54 55 if (activeRegistrations.length === 0) { 56 return fallback ?? null 57 } 58 59 return ( 60 <> 61 {activeRegistrations.map((reg) => { 62 const PluginComponent = reg.component as ComponentType<Record<string, unknown>> 63 return ( 64 <PluginErrorBoundary key={reg.pluginName} pluginName={reg.pluginName}> 65 <PluginComponent {...context} /> 66 </PluginErrorBoundary> 67 ) 68 })} 69 </> 70 ) 71}