diff --git a/.eslintrc.js b/.eslintrc.js index 27efc2178f96..283e5036380f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,5 +11,6 @@ config.rules['unicorn/explicit-length-check'] = 0; config.rules['unicorn/prefer-code-point'] = 0; config.rules['no-extra-boolean-cast'] = 0; config.rules['unicorn/no-useless-undefined'] = 0; +config.rules['react/no-unknown-property'] = 0; module.exports = config; diff --git a/locales/en_US/plugin.json b/locales/en_US/plugin.json index 1df39d4c3647..b0b86bac8aee 100644 --- a/locales/en_US/plugin.json +++ b/locales/en_US/plugin.json @@ -52,7 +52,11 @@ "desc": "LobeChat will install the plugin using this link", "invalid": "The input manifest link is invalid or does not comply with the specification", "label": "Plugin Manifest URL", - "urlError": "Please enter a valid URL" + "urlError": "Please enter a valid URL", + "jsonInvalid": "The manifest is not valid, validation result: \n\n {{error}}", + "preview": "Preview Manifest", + "refresh": "Refresh", + "requestError": "Failed to request the link, please enter a valid link and check if the link allows cross-origin access" }, "title": { "desc": "The title of the plugin", @@ -73,7 +77,9 @@ "manifest": "Function Description Manifest (Manifest)", "meta": "Plugin Metadata" }, - "title": "Add Custom Plugin" + "title": "Add Custom Plugin", + "update": "Update", + "updateSuccess": "Plugin settings updated successfully" }, "list": { "item": { diff --git a/package.json b/package.json index 88b714453ec6..9f4ab3150f33 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "@emoji-mart/data": "^1", "@emoji-mart/react": "^1", "@icons-pack/react-simple-icons": "^9", - "@lobehub/chat-plugin-sdk": "^1.13.1", + "@lobehub/chat-plugin-sdk": "^1.15.0", "@lobehub/chat-plugins-gateway": "^1.5.0", "@lobehub/ui": "latest", "@vercel/analytics": "^1", diff --git a/src/pages/chat/features/Conversation/ChatList/Plugins/IFrameRender/hooks.ts b/src/pages/chat/features/Conversation/ChatList/Plugins/IFrameRender/hooks.ts new file mode 100644 index 000000000000..7339f4773fb6 --- /dev/null +++ b/src/pages/chat/features/Conversation/ChatList/Plugins/IFrameRender/hooks.ts @@ -0,0 +1,29 @@ +import { useEffect } from 'react'; + +import { onPluginFetchMessage, onPluginReady } from './utils'; + +export const useOnPluginReady = (onReady: () => void) => { + useEffect(() => { + const fn = (e: MessageEvent) => { + onPluginReady(e, onReady); + }; + + window.addEventListener('message', fn); + return () => { + window.removeEventListener('message', fn); + }; + }, []); +}; + +export const useOnPluginFetchMessage = (onRequest: (data: any) => void, deps: any[] = []) => { + useEffect(() => { + const fn = (e: MessageEvent) => { + onPluginFetchMessage(e, onRequest); + }; + + window.addEventListener('message', fn); + return () => { + window.removeEventListener('message', fn); + }; + }, deps); +}; diff --git a/src/pages/chat/features/Conversation/ChatList/Plugins/IFrameRender/index.tsx b/src/pages/chat/features/Conversation/ChatList/Plugins/IFrameRender/index.tsx new file mode 100644 index 000000000000..9eebe0bb403d --- /dev/null +++ b/src/pages/chat/features/Conversation/ChatList/Plugins/IFrameRender/index.tsx @@ -0,0 +1,62 @@ +import { PluginRenderProps } from '@lobehub/chat-plugin-sdk'; +import { Skeleton } from 'antd'; +import { memo, useEffect, useRef, useState } from 'react'; + +import { useOnPluginFetchMessage, useOnPluginReady } from './hooks'; +import { sendMessageToPlugin } from './utils'; + +interface IFrameRenderProps extends PluginRenderProps { + height?: number; + url: string; + width?: number; +} + +const IFrameRender = memo(({ url, width = 800, height = 300, ...props }) => { + const [loading, setLoading] = useState(true); + const [readyForRender, setReady] = useState(false); + const iframeRef = useRef(null); + + useOnPluginReady(() => setReady(true)); + + // 当 props 发生变化时,主动向 iframe 发送数据 + useEffect(() => { + const iframeWin = iframeRef.current?.contentWindow; + + if (iframeWin && readyForRender) { + sendMessageToPlugin(iframeWin, props); + } + }, [readyForRender, props]); + + // 当接收到来自 iframe 的请求时,触发发送数据 + useOnPluginFetchMessage(() => { + const iframeWin = iframeRef.current?.contentWindow; + if (iframeWin) { + sendMessageToPlugin(iframeWin, props); + } + }, [props]); + + return ( + <> + {loading && } +