feat(iframe): add iframe bridge for ragflow integration
- Implement Penpal-based iframe communication bridge between host and child apps - Add route handling for ragflow integration with '/route-ragflow' prefix - Update navigation hooks to support embedded mode via iframe bridge - Configure build and dependencies for new iframe-bridge package - Adjust nginx config for proper SPA routing in subpath deployments
This commit is contained in:
@@ -108,7 +108,7 @@ function AgentListPage() {
|
||||
onCreateAgent={() => setCreateOpen(true)}
|
||||
onEdit={(agent) => { setEditTarget(agent); setEditOpen(true); }}
|
||||
onView={(agent) => {
|
||||
navigate(`/agent/${agent.id}`);
|
||||
navigate(`/route-ragflow/agent/${agent.id}`);
|
||||
}}
|
||||
onDelete={async (agent) => {
|
||||
const confirmed = await dialog.confirm({
|
||||
|
||||
40
src/pages/ragflow/agent.tsx
Normal file
40
src/pages/ragflow/agent.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { createPenpalHostBridge } from '@teres/iframe-bridge';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
export default function RagflowAgentPage() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const navigate = useNavigate();
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
const src = useMemo(() => `/ragflow/agent/${id ?? ''}`, [id]);
|
||||
|
||||
logger.info('RagflowAgentPage', id, src);
|
||||
|
||||
useEffect(() => {
|
||||
const el = iframeRef.current;
|
||||
if (!el) return;
|
||||
const { destroy } = createPenpalHostBridge({
|
||||
iframe: el,
|
||||
methods: {
|
||||
navigate: (to: string) => navigate(to),
|
||||
close: () => navigate('/agents'),
|
||||
agentReady: () => {
|
||||
// 可选:在需要时记录或触发后续逻辑
|
||||
},
|
||||
},
|
||||
});
|
||||
return () => destroy();
|
||||
}, [navigate]);
|
||||
|
||||
// 如需兼容旧的 postMessage 事件,可保留以下监听;为了纯 Penpal,此处移除
|
||||
|
||||
return (
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
title="ragflow-agent"
|
||||
src={src}
|
||||
style={{ width: '100%', height: '100vh', border: 'none' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
37
src/pages/ragflow/iframe.tsx
Normal file
37
src/pages/ragflow/iframe.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { createPenpalHostBridge, toChildPath } from '@teres/iframe-bridge';
|
||||
|
||||
export default function RagflowIframePage() {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
// 将宿主的 "/route-ragflow/**" 路径转换为子应用的 "/ragflow/**" 路径
|
||||
const childPath = toChildPath(location.pathname);
|
||||
const src = `/ragflow${childPath}${location.search}${location.hash}`;
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const el = iframeRef.current;
|
||||
if (!el) return;
|
||||
const { destroy } = createPenpalHostBridge({
|
||||
iframe: el,
|
||||
methods: {
|
||||
navigate: (to: string) => navigate(to),
|
||||
close: () => navigate('/agents'),
|
||||
agentReady: () => {
|
||||
// 可选:记录或触发后续逻辑
|
||||
},
|
||||
},
|
||||
});
|
||||
return () => destroy();
|
||||
}, [navigate, src]);
|
||||
|
||||
return (
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
title="ragflow"
|
||||
src={src}
|
||||
style={{ width: '100%', height: '100vh', border: 'none' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
9
src/pages/ragflow/layout.tsx
Normal file
9
src/pages/ragflow/layout.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
export default function RagflowLayout() {
|
||||
return (
|
||||
<div style={{ width: '100%', height: '100vh' }}>
|
||||
<Outlet />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user