mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Click the edit tool button of the agent form to open the corresponding form #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -116,6 +116,7 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) {
|
|||||||
runVisible,
|
runVisible,
|
||||||
hideRunOrChatDrawer,
|
hideRunOrChatDrawer,
|
||||||
showChatModal,
|
showChatModal,
|
||||||
|
showFormDrawer,
|
||||||
} = useShowDrawer({
|
} = useShowDrawer({
|
||||||
drawerVisible,
|
drawerVisible,
|
||||||
hideDrawer,
|
hideDrawer,
|
||||||
@ -175,7 +176,7 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) {
|
|||||||
</marker>
|
</marker>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
<AgentInstanceContext.Provider value={{ addCanvasNode }}>
|
<AgentInstanceContext.Provider value={{ addCanvasNode, showFormDrawer }}>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
connectionMode={ConnectionMode.Loose}
|
connectionMode={ConnectionMode.Loose}
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
@ -228,7 +229,9 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) {
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
></NotebookPen>
|
></NotebookPen>
|
||||||
{formDrawerVisible && (
|
{formDrawerVisible && (
|
||||||
<AgentInstanceContext.Provider value={{ addCanvasNode }}>
|
<AgentInstanceContext.Provider
|
||||||
|
value={{ addCanvasNode, showFormDrawer }}
|
||||||
|
>
|
||||||
<FormSheet
|
<FormSheet
|
||||||
node={clickedNode}
|
node={clickedNode}
|
||||||
visible={formDrawerVisible}
|
visible={formDrawerVisible}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { HandleType, Position } from '@xyflow/react';
|
|||||||
import { createContext } from 'react';
|
import { createContext } from 'react';
|
||||||
import { useAddNode } from './hooks/use-add-node';
|
import { useAddNode } from './hooks/use-add-node';
|
||||||
import { useCacheChatLog } from './hooks/use-cache-chat-log';
|
import { useCacheChatLog } from './hooks/use-cache-chat-log';
|
||||||
import { useShowLogSheet } from './hooks/use-show-drawer';
|
import { useShowFormDrawer, useShowLogSheet } from './hooks/use-show-drawer';
|
||||||
|
|
||||||
export const AgentFormContext = createContext<RAGFlowNodeType | undefined>(
|
export const AgentFormContext = createContext<RAGFlowNodeType | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
@ -12,7 +12,8 @@ export const AgentFormContext = createContext<RAGFlowNodeType | undefined>(
|
|||||||
type AgentInstanceContextType = Pick<
|
type AgentInstanceContextType = Pick<
|
||||||
ReturnType<typeof useAddNode>,
|
ReturnType<typeof useAddNode>,
|
||||||
'addCanvasNode'
|
'addCanvasNode'
|
||||||
>;
|
> &
|
||||||
|
Pick<ReturnType<typeof useShowFormDrawer>, 'showFormDrawer'>;
|
||||||
|
|
||||||
export const AgentInstanceContext = createContext<AgentInstanceContextType>(
|
export const AgentInstanceContext = createContext<AgentInstanceContextType>(
|
||||||
{} as AgentInstanceContextType,
|
{} as AgentInstanceContextType,
|
||||||
|
|||||||
@ -2,7 +2,13 @@ import { BlockButton } from '@/components/ui/button';
|
|||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { Position } from '@xyflow/react';
|
import { Position } from '@xyflow/react';
|
||||||
import { PencilLine, X } from 'lucide-react';
|
import { PencilLine, X } from 'lucide-react';
|
||||||
import { PropsWithChildren, useCallback, useContext, useMemo } from 'react';
|
import {
|
||||||
|
MouseEventHandler,
|
||||||
|
PropsWithChildren,
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useMemo,
|
||||||
|
} from 'react';
|
||||||
import { Operator } from '../../constant';
|
import { Operator } from '../../constant';
|
||||||
import { AgentInstanceContext } from '../../context';
|
import { AgentInstanceContext } from '../../context';
|
||||||
import { useFindMcpById } from '../../hooks/use-find-mcp-by-id';
|
import { useFindMcpById } from '../../hooks/use-find-mcp-by-id';
|
||||||
@ -35,23 +41,20 @@ export function ToolCard({
|
|||||||
type ActionButtonProps<T> = {
|
type ActionButtonProps<T> = {
|
||||||
record: T;
|
record: T;
|
||||||
deleteRecord(record: T): void;
|
deleteRecord(record: T): void;
|
||||||
edit(record: T): void;
|
edit: MouseEventHandler<HTMLOrSVGElement>;
|
||||||
};
|
};
|
||||||
|
|
||||||
function ActionButton<T>({ edit, deleteRecord, record }: ActionButtonProps<T>) {
|
function ActionButton<T>({ deleteRecord, record, edit }: ActionButtonProps<T>) {
|
||||||
const handleDelete = useCallback(() => {
|
const handleDelete = useCallback(() => {
|
||||||
deleteRecord(record);
|
deleteRecord(record);
|
||||||
}, [deleteRecord, record]);
|
}, [deleteRecord, record]);
|
||||||
const handleEdit = useCallback(() => {
|
|
||||||
edit(record);
|
|
||||||
}, [edit, record]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2 text-text-sub-title">
|
<div className="flex items-center gap-2 text-text-sub-title">
|
||||||
<PencilLine
|
<PencilLine
|
||||||
className="size-4 cursor-pointer"
|
className="size-4 cursor-pointer"
|
||||||
data-tool={record}
|
data-tool={record}
|
||||||
onClick={handleEdit}
|
onClick={edit}
|
||||||
/>
|
/>
|
||||||
<X className="size-4 cursor-pointer" onClick={handleDelete} />
|
<X className="size-4 cursor-pointer" onClick={handleDelete} />
|
||||||
</div>
|
</div>
|
||||||
@ -64,6 +67,21 @@ export function AgentTools() {
|
|||||||
const { mcpIds } = useGetAgentMCPIds();
|
const { mcpIds } = useGetAgentMCPIds();
|
||||||
const { findMcpById } = useFindMcpById();
|
const { findMcpById } = useFindMcpById();
|
||||||
const { deleteNodeMCP } = useDeleteAgentNodeMCP();
|
const { deleteNodeMCP } = useDeleteAgentNodeMCP();
|
||||||
|
const { showFormDrawer } = useContext(AgentInstanceContext);
|
||||||
|
const { clickedNodeId, findAgentToolNodeById, selectNodeIds } = useGraphStore(
|
||||||
|
(state) => state,
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleEdit: MouseEventHandler<SVGSVGElement> = useCallback(
|
||||||
|
(e) => {
|
||||||
|
const toolNodeId = findAgentToolNodeById(clickedNodeId);
|
||||||
|
if (toolNodeId) {
|
||||||
|
selectNodeIds([toolNodeId]);
|
||||||
|
showFormDrawer(e, toolNodeId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[clickedNodeId, findAgentToolNodeById, selectNodeIds, showFormDrawer],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="space-y-2.5">
|
<section className="space-y-2.5">
|
||||||
@ -74,8 +92,8 @@ export function AgentTools() {
|
|||||||
{x}
|
{x}
|
||||||
<ActionButton
|
<ActionButton
|
||||||
record={x}
|
record={x}
|
||||||
edit={() => {}}
|
|
||||||
deleteRecord={deleteNodeTool(x)}
|
deleteRecord={deleteNodeTool(x)}
|
||||||
|
edit={handleEdit}
|
||||||
></ActionButton>
|
></ActionButton>
|
||||||
</ToolCard>
|
</ToolCard>
|
||||||
))}
|
))}
|
||||||
@ -84,8 +102,8 @@ export function AgentTools() {
|
|||||||
{findMcpById(id)?.name}
|
{findMcpById(id)?.name}
|
||||||
<ActionButton
|
<ActionButton
|
||||||
record={id}
|
record={id}
|
||||||
edit={() => {}}
|
|
||||||
deleteRecord={deleteNodeMCP(id)}
|
deleteRecord={deleteNodeMCP(id)}
|
||||||
|
edit={handleEdit}
|
||||||
></ActionButton>
|
></ActionButton>
|
||||||
</ToolCard>
|
</ToolCard>
|
||||||
))}
|
))}
|
||||||
@ -99,8 +117,17 @@ export function AgentTools() {
|
|||||||
|
|
||||||
export function Agents({ node }: INextOperatorForm) {
|
export function Agents({ node }: INextOperatorForm) {
|
||||||
const { addCanvasNode } = useContext(AgentInstanceContext);
|
const { addCanvasNode } = useContext(AgentInstanceContext);
|
||||||
const { deleteAgentDownstreamNodesById, edges, getNode } = useGraphStore(
|
const { deleteAgentDownstreamNodesById, edges, getNode, selectNodeIds } =
|
||||||
(state) => state,
|
useGraphStore((state) => state);
|
||||||
|
const { showFormDrawer } = useContext(AgentInstanceContext);
|
||||||
|
|
||||||
|
const handleEdit = useCallback(
|
||||||
|
(nodeId: string): MouseEventHandler<SVGSVGElement> =>
|
||||||
|
(e) => {
|
||||||
|
selectNodeIds([nodeId]);
|
||||||
|
showFormDrawer(e, nodeId);
|
||||||
|
},
|
||||||
|
[selectNodeIds, showFormDrawer],
|
||||||
);
|
);
|
||||||
|
|
||||||
const subBottomAgentNodeIds = useMemo(() => {
|
const subBottomAgentNodeIds = useMemo(() => {
|
||||||
@ -119,8 +146,8 @@ export function Agents({ node }: INextOperatorForm) {
|
|||||||
{currentNode?.data.name}
|
{currentNode?.data.name}
|
||||||
<ActionButton
|
<ActionButton
|
||||||
record={id}
|
record={id}
|
||||||
edit={() => {}}
|
|
||||||
deleteRecord={deleteAgentDownstreamNodesById}
|
deleteRecord={deleteAgentDownstreamNodesById}
|
||||||
|
edit={handleEdit(id)}
|
||||||
></ActionButton>
|
></ActionButton>
|
||||||
</ToolCard>
|
</ToolCard>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -40,7 +40,7 @@ export function useUpdateAgentNodeMCP() {
|
|||||||
} else if (tools) {
|
} else if (tools) {
|
||||||
pre.push({
|
pre.push({
|
||||||
mcp_id: cur,
|
mcp_id: cur,
|
||||||
tools,
|
tools: {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return pre;
|
return pre;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useSetModalState } from '@/hooks/common-hooks';
|
import { useSetModalState } from '@/hooks/common-hooks';
|
||||||
import { Node, NodeMouseHandler } from '@xyflow/react';
|
import { NodeMouseHandler } from '@xyflow/react';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { useCallback, useEffect } from 'react';
|
import React, { useCallback, useEffect } from 'react';
|
||||||
import { Operator } from '../constant';
|
import { Operator } from '../constant';
|
||||||
import useGraphStore from '../store';
|
import useGraphStore from '../store';
|
||||||
import { useCacheChatLog } from './use-cache-chat-log';
|
import { useCacheChatLog } from './use-cache-chat-log';
|
||||||
@ -21,9 +21,9 @@ export const useShowFormDrawer = () => {
|
|||||||
showModal: showFormDrawer,
|
showModal: showFormDrawer,
|
||||||
} = useSetModalState();
|
} = useSetModalState();
|
||||||
|
|
||||||
const handleShow: NodeMouseHandler = useCallback(
|
const handleShow = useCallback(
|
||||||
(e, node: Node) => {
|
(e: React.MouseEvent<Element>, nodeId: string) => {
|
||||||
setClickedNodeId(node.id);
|
setClickedNodeId(nodeId);
|
||||||
setClickedToolId(get(e.target, 'dataset.tool'));
|
setClickedToolId(get(e.target, 'dataset.tool'));
|
||||||
showFormDrawer();
|
showFormDrawer();
|
||||||
},
|
},
|
||||||
@ -118,7 +118,7 @@ export function useShowDrawer({
|
|||||||
if (!ExcludedNodes.some((x) => x === node.data.label)) {
|
if (!ExcludedNodes.some((x) => x === node.data.label)) {
|
||||||
hideSingleDebugDrawer();
|
hideSingleDebugDrawer();
|
||||||
// hideRunOrChatDrawer();
|
// hideRunOrChatDrawer();
|
||||||
showFormDrawer(e, node);
|
showFormDrawer(e, node.id);
|
||||||
}
|
}
|
||||||
// handle single debug icon click
|
// handle single debug icon click
|
||||||
if (
|
if (
|
||||||
|
|||||||
@ -85,6 +85,8 @@ export type RFState = {
|
|||||||
setClickedToolId: (id?: string) => void;
|
setClickedToolId: (id?: string) => void;
|
||||||
findUpstreamNodeById: (id?: string | null) => RAGFlowNodeType | undefined;
|
findUpstreamNodeById: (id?: string | null) => RAGFlowNodeType | undefined;
|
||||||
deleteCategorizeCaseEdges: (source: string, sourceHandle: string) => void; // Deleting a condition of a classification operator will delete the related edge
|
deleteCategorizeCaseEdges: (source: string, sourceHandle: string) => void; // Deleting a condition of a classification operator will delete the related edge
|
||||||
|
findAgentToolNodeById: (id: string | null) => string | undefined;
|
||||||
|
selectNodeIds: (nodeIds: string[]) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// this is our useStore hook that we can use in our components to get parts of the store and call actions
|
// this is our useStore hook that we can use in our components to get parts of the store and call actions
|
||||||
@ -518,6 +520,22 @@ const useGraphStore = create<RFState>()(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
findAgentToolNodeById: (id) => {
|
||||||
|
const { edges } = get();
|
||||||
|
return edges.find(
|
||||||
|
(edge) =>
|
||||||
|
edge.source === id && edge.sourceHandle === NodeHandleId.Tool,
|
||||||
|
)?.target;
|
||||||
|
},
|
||||||
|
selectNodeIds: (nodeIds) => {
|
||||||
|
const { nodes, setNodes } = get();
|
||||||
|
setNodes(
|
||||||
|
nodes.map((node) => ({
|
||||||
|
...node,
|
||||||
|
selected: nodeIds.includes(node.id),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
},
|
||||||
})),
|
})),
|
||||||
{ name: 'graph', trace: true },
|
{ name: 'graph', trace: true },
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user