refactor(block-h): message block types resolve via plugin-contributable registry

This commit is contained in:
Agent Zero
2026-08-23 13:45:12 +02:00
parent 49949066d3
commit b7ad5294a5
3 changed files with 72 additions and 25 deletions
@@ -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,23 +45,13 @@ const BlockRenderer: React.FC<BlockRendererProps> = ({ blocks }) => {
return <VideoBlock block={block} />;
case 'file':
return <FileBlock block={block} />;
case 'action_card':
return <ActionCardBlock block={block} />;
case 'contact_card':
return <ContactCardBlock block={block} />;
case 'miniapp':
return <MiniAppBlock block={block} />;
case 'agent_result':
return <AgentResultBlock block={block} />;
case 'approval_request':
return <ApprovalRequestBlock block={block} />;
case 'task_card':
return <TaskCardBlock block={block} />;
case 'workflow_card':
return <WorkflowCardBlock block={block} />;
case 'knowledge_card':
return <KnowledgeCardBlock block={block} />;
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 <ContributedBlock block={block} />;
}
// Fallback for unknown block types
return (
<div className="text-xs text-secondary-400 italic p-2 rounded bg-secondary-50">
@@ -75,6 +59,7 @@ const BlockRenderer: React.FC<BlockRendererProps> = ({ blocks }) => {
</div>
);
}
}
};
return (
@@ -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');
@@ -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<string, BlockComponent>();
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);
}