diff --git a/frontend/src/components/comm/blocks/BlockRenderer.tsx b/frontend/src/components/comm/blocks/BlockRenderer.tsx index dc1f43c..f3c4823 100644 --- a/frontend/src/components/comm/blocks/BlockRenderer.tsx +++ b/frontend/src/components/comm/blocks/BlockRenderer.tsx @@ -6,14 +6,8 @@ import ImageBlock from './ImageBlock'; import AudioBlock from './AudioBlock'; import VideoBlock from './VideoBlock'; import FileBlock from './FileBlock'; -import ActionCardBlock from './ActionCardBlock'; -import ContactCardBlock from './ContactCardBlock'; -import MiniAppBlock from './MiniAppBlock'; -import AgentResultBlock from './AgentResultBlock'; -import ApprovalRequestBlock from './ApprovalRequestBlock'; -import TaskCardBlock from './TaskCardBlock'; -import WorkflowCardBlock from './WorkflowCardBlock'; -import KnowledgeCardBlock from './KnowledgeCardBlock'; +import { getBlockComponent } from './registry'; +import './registrations'; // plugin-contributed block registrations interface BlockRendererProps { blocks: MessageBlock[]; @@ -51,29 +45,20 @@ const BlockRenderer: React.FC = ({ blocks }) => { return ; case 'file': return ; - case 'action_card': - return ; - case 'contact_card': - return ; - case 'miniapp': - return ; - case 'agent_result': - return ; - case 'approval_request': - return ; - case 'task_card': - return ; - case 'workflow_card': - return ; - case 'knowledge_card': - return ; - default: + default: { + // Plugin-contributed block types (Block H / HC-F) + const Contributed = getBlockComponent(block.block_type); + if (Contributed) { + const ContributedBlock = Contributed as React.FC<{ block: MessageBlock }>; + return ; + } // Fallback for unknown block types return (
Unbekannter Block-Typ: {block.block_type}
); + } } }; diff --git a/frontend/src/components/comm/blocks/registrations.ts b/frontend/src/components/comm/blocks/registrations.ts new file mode 100644 index 0000000..2046b76 --- /dev/null +++ b/frontend/src/components/comm/blocks/registrations.ts @@ -0,0 +1,26 @@ +/** + * Plugin block registrations. + * + * Currently a static import list; the dynamic plugin loader (ARCH-019 fix) + * will replace this file with manifest-driven registration. Plugins register + * their block renderers via ``registerBlockType`` with an owner tag so that + * ``unregisterBlockTypes(owner)`` can clean up on deactivation. + */ +import { registerBlockType } from './registry'; +import ActionCardBlock from './ActionCardBlock'; +import ContactCardBlock from './ContactCardBlock'; +import MiniAppBlock from './MiniAppBlock'; +import AgentResultBlock from './AgentResultBlock'; +import ApprovalRequestBlock from './ApprovalRequestBlock'; +import TaskCardBlock from './TaskCardBlock'; +import WorkflowCardBlock from './WorkflowCardBlock'; +import KnowledgeCardBlock from './KnowledgeCardBlock'; + +registerBlockType('action_card', ActionCardBlock, 'core-comm'); +registerBlockType('contact_card', ContactCardBlock, 'contacts'); +registerBlockType('miniapp', MiniAppBlock, 'kommunikation'); +registerBlockType('agent_result', AgentResultBlock, 'automation'); +registerBlockType('approval_request', ApprovalRequestBlock, 'core-approvals'); +registerBlockType('task_card', TaskCardBlock, 'tasks'); +registerBlockType('workflow_card', WorkflowCardBlock, 'workflows'); +registerBlockType('knowledge_card', KnowledgeCardBlock, 'knowledge'); diff --git a/frontend/src/components/comm/blocks/registry.ts b/frontend/src/components/comm/blocks/registry.ts new file mode 100644 index 0000000..534d408 --- /dev/null +++ b/frontend/src/components/comm/blocks/registry.ts @@ -0,0 +1,36 @@ +/** + * Message block type registry. + * + * Core owns the base block types; plugins can contribute additional block + * renderers via ``registerBlockType`` / ``unregisterBlockTypes`` during their + * frontend activation lifecycle (Block H / HC-F). + */ +import type { ComponentType } from 'react'; +import type { MessageBlock } from '@/store/commStore'; + +export type BlockComponent = ComponentType<{ block: MessageBlock }>; + +const _registry = new Map(); + +export function registerBlockType(blockType: string, component: BlockComponent, owner = ''): void { + if (_registry.has(blockType)) { + // eslint-disable-next-line no-console + console.warn(`[blockRegistry] block type '${blockType}' re-registered by '${owner || 'unknown'}' — overwriting`); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (component as any).__block_owner__ = owner; + _registry.set(blockType, component); +} + +export function unregisterBlockTypes(owner: string): void { + for (const [key, component] of _registry.entries()) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if ((component as any).__block_owner__ === owner) { + _registry.delete(key); + } + } +} + +export function getBlockComponent(blockType: string): BlockComponent | undefined { + return _registry.get(blockType); +}