feat(plugins): implement plugin loading and management system
- Added PluginLoader component to dynamically load and initialize plugins. - Created Plugins component for managing installed and marketplace plugins. - Introduced PluginAPI for plugin interaction and settings management. - Defined types for plugin metadata, installed plugins, and plugin index. - Implemented settings rendering for plugins based on their schema. - Integrated marketplace plugin fetching and installation logic. - Added support for enabling/disabling and uninstalling plugins.
This commit is contained in:
@@ -102,6 +102,7 @@ import {
|
||||
import { getMemberDisplayName, getMentionContent, trimReplyFromBody } from '../../utils/room';
|
||||
import { CommandAutocomplete } from './CommandAutocomplete';
|
||||
import { Command, SHRUG, TABLEFLIP, UNFLIP, useCommands } from '../../hooks/useCommands';
|
||||
import { pluginRegistry } from '../settings/plugins/PluginAPI';
|
||||
import { mobileOrTablet } from '../../utils/user-agent';
|
||||
import { useElementSizeObserver } from '../../hooks/useElementSizeObserver';
|
||||
import { ReplyLayout, ThreadIndicator } from '../../components/message';
|
||||
@@ -308,7 +309,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
contents.forEach((content) => mx.sendMessage(roomId, content as any));
|
||||
};
|
||||
|
||||
const submit = useCallback(() => {
|
||||
const submit = useCallback(async () => {
|
||||
uploadBoardHandlers.current?.handleSend();
|
||||
|
||||
const commandName = getBeginCommand(editor);
|
||||
@@ -340,9 +341,30 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
plainText = `${UNFLIP} ${plainText}`;
|
||||
customHtml = `${UNFLIP} ${customHtml}`;
|
||||
} else if (commandName) {
|
||||
// Check built-in commands first
|
||||
const commandContent = commands[commandName as Command];
|
||||
if (commandContent) {
|
||||
commandContent.exe(plainText);
|
||||
resetEditor(editor);
|
||||
resetEditorHistory(editor);
|
||||
sendTypingStatus(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check plugin commands
|
||||
try {
|
||||
const result = await pluginRegistry.executeCommand(commandName, plainText);
|
||||
if (result) {
|
||||
// If command returns text, send it as a message
|
||||
const content: IContent = {
|
||||
msgtype: MsgType.Text,
|
||||
body: result,
|
||||
};
|
||||
mx.sendMessage(roomId, content as any);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`[RoomInput] Plugin command /${commandName} failed:`, err);
|
||||
// Show error to user (could integrate with notification system)
|
||||
}
|
||||
resetEditor(editor);
|
||||
resetEditorHistory(editor);
|
||||
@@ -398,6 +420,27 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
|
||||
'm.in_reply_to': { event_id: threadRootId },
|
||||
};
|
||||
}
|
||||
|
||||
// Process message through plugin interceptors
|
||||
try {
|
||||
const messageContext = {
|
||||
content: content.body,
|
||||
roomId,
|
||||
eventType: 'm.room.message',
|
||||
formatted: content.formatted_body,
|
||||
metadata: {},
|
||||
};
|
||||
const processedContext = await pluginRegistry.processBeforeSend(messageContext);
|
||||
|
||||
// Update content with intercepted values
|
||||
content.body = processedContext.content;
|
||||
if (processedContext.formatted) {
|
||||
content.formatted_body = processedContext.formatted;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('[RoomInput] Plugin interceptor error:', err);
|
||||
}
|
||||
|
||||
mx.sendMessage(roomId, content as any);
|
||||
resetEditor(editor);
|
||||
resetEditorHistory(editor);
|
||||
|
||||
Reference in New Issue
Block a user