11"use client"
22
3- import React , { useState , useEffect , useCallback , useRef } from 'react'
4- import { Modal , Spin , message , Typography } from 'antd'
5- import { RobotOutlined , ToolOutlined } from '@ant-design/icons'
6- import { useTranslation } from 'react-i18next'
7- import { fetchAgentCallRelationship } from '@/services/agentConfigService'
8- import Tree from 'react-d3-tree' ;
3+ import React , { useState , useEffect , useCallback , useRef } from "react"
4+ import { Modal , Spin , message , Typography } from "antd"
5+ import { RobotOutlined , ToolOutlined } from "@ant-design/icons"
6+ import { useTranslation } from "react-i18next"
7+ import { fetchAgentCallRelationship } from "@/services/agentConfigService"
8+ import Tree from "react-d3-tree"
9+ import {
10+ AgentCallRelationship ,
11+ AgentCallRelationshipSubAgent ,
12+ AgentCallRelationshipTool ,
13+ AgentCallRelationshipModalProps ,
14+ AgentCallRelationshipTreeNodeDatum
15+ } from "@/types/agentConfig"
916
1017const { Text } = Typography
1118
12- interface Tool {
13- tool_id : string
14- name : string
15- type : string
16- }
17-
18- interface SubAgent {
19- agent_id : string
20- name : string
21- tools : Tool [ ]
22- sub_agents : SubAgent [ ]
23- depth ?: number
24- }
25-
26- interface AgentCallRelationship {
27- agent_id : string
28- name : string
29- tools : Tool [ ]
30- sub_agents : SubAgent [ ]
31- }
32-
33- interface AgentCallRelationshipModalProps {
34- visible : boolean
35- onClose : ( ) => void
36- agentId : number
37- agentName : string
38- }
39-
4019/** Consistent with custom node visual dimensions (convenient for line endings at edges) */
4120const NODE_W = 140 ;
4221const NODE_H = 60 ;
@@ -99,19 +78,19 @@ const getNodeColor = (type: string, depth: number = 0) => {
9978
10079// Custom node - center aligned, unified font style
10180const CustomNode = ( { nodeDatum } : any ) => {
102- const isAgent = nodeDatum . type === ' main' || nodeDatum . type === ' sub' ;
81+ const isAgent = nodeDatum . type === " main" || nodeDatum . type === " sub" ;
10382 const color = getNodeColor ( nodeDatum . type , nodeDatum . depth ) ;
10483 const icon = isAgent ? < RobotOutlined /> : < ToolOutlined /> ;
10584
10685 // Truncate tool names by maximum character count (avoid too long)
107- const rawName : string = nodeDatum . name || '' ;
86+ const rawName : string = nodeDatum . name || "" ;
10887 const displayName : string = ! isAgent
10988 ? truncateByCodePoints ( rawName , MAX_TOOL_NAME_CHARS )
11089 : rawName ;
11190
11291 // Unified font
113- const fontSize = isAgent ? ' 14px' : ' 12px' ;
114- const fontWeight = isAgent ? ' 600' : ' 500' ;
92+ const fontSize = isAgent ? " 14px" : " 12px" ;
93+ const fontWeight = isAgent ? " 600" : " 500" ;
11594
11695 // —— Unified dimensions: Agent rectangles, Tool gears fixed size ——
11796 const nodeWidth = isAgent ? AGENT_W : TOOL_SIZE ;
@@ -131,8 +110,8 @@ const CustomNode = ({ nodeDatum }: any) => {
131110 stroke = { `${ color } 80` }
132111 strokeWidth = { 1.5 }
133112 style = { {
134- transition : ' all 0.3s ease' ,
135- filter : ' drop-shadow(0 3px 6px rgba(0,0,0,0.12))'
113+ transition : " all 0.3s ease" ,
114+ filter : " drop-shadow(0 3px 6px rgba(0,0,0,0.12))"
136115 } }
137116 />
138117 ) ;
@@ -149,19 +128,19 @@ const CustomNode = ({ nodeDatum }: any) => {
149128 const r = i % 2 === 0 ? outerRadius : outerRadius - teethDepth ;
150129 const x = cx + r * Math . cos ( angle ) ;
151130 const y = cy + r * Math . sin ( angle ) ;
152- d . push ( `${ i === 0 ? 'M' : 'L' } ${ x } ${ y } ` ) ;
131+ d . push ( `${ i === 0 ? "M" : "L" } ${ x } ${ y } ` ) ;
153132 }
154- d . push ( 'Z' ) ;
133+ d . push ( "Z" ) ;
155134
156135 return (
157136 < path
158- d = { d . join ( ' ' ) }
137+ d = { d . join ( " " ) }
159138 fill = { color }
160139 stroke = { `${ color } 80` }
161140 strokeWidth = { 1.5 }
162141 style = { {
163- transition : ' all 0.3s ease' ,
164- filter : ' drop-shadow(0 2px 4px rgba(0,0,0,0.10))'
142+ transition : " all 0.3s ease" ,
143+ filter : " drop-shadow(0 2px 4px rgba(0,0,0,0.10))"
165144 } }
166145 />
167146 ) ;
@@ -177,45 +156,45 @@ const CustomNode = ({ nodeDatum }: any) => {
177156 y = { 0 }
178157 width = { nodeWidth }
179158 height = { nodeHeight }
180- style = { { overflow : ' hidden' , borderRadius : isAgent ? 14 : nodeWidth / 2 } }
159+ style = { { overflow : " hidden" , borderRadius : isAgent ? 14 : nodeWidth / 2 } }
181160 >
182161 < div
183162 style = { {
184- width : ' 100%' ,
185- height : ' 100%' ,
186- display : ' flex' ,
187- alignItems : ' center' ,
188- justifyContent : ' center' ,
189- gap : ' 6px' ,
190- padding : isAgent ? ' 0 16px' : ' 0 12px' ,
163+ width : " 100%" ,
164+ height : " 100%" ,
165+ display : " flex" ,
166+ alignItems : " center" ,
167+ justifyContent : " center" ,
168+ gap : " 6px" ,
169+ padding : isAgent ? " 0 16px" : " 0 12px" ,
191170 fontSize,
192- color : isAgent ? ' #ffffff' : ' #1e293b' ,
193- fontFamily : ' -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif' ,
171+ color : isAgent ? " #ffffff" : " #1e293b" ,
172+ fontFamily : " -apple-system, BlinkMacSystemFont, \ "Segoe UI\ ", Roboto, sans-serif" ,
194173 fontWeight,
195- textAlign : ' center' ,
174+ textAlign : " center" ,
196175 lineHeight : 1 ,
197- userSelect : ' none' ,
198- letterSpacing : ' 0.02em' ,
199- whiteSpace : ' nowrap' ,
176+ userSelect : " none" ,
177+ letterSpacing : " 0.02em" ,
178+ whiteSpace : " nowrap" ,
200179 } }
201180 >
202181 < span style = { {
203- display : ' inline-flex' ,
204- width : isAgent ? ' 18px' : ' 16px' ,
205- height : isAgent ? ' 18px' : ' 16px' ,
206- alignItems : ' center' ,
207- justifyContent : ' center' ,
208- transform : ' translateY(-0.5px)' ,
209- flex : ' 0 0 auto'
182+ display : " inline-flex" ,
183+ width : isAgent ? " 18px" : " 16px" ,
184+ height : isAgent ? " 18px" : " 16px" ,
185+ alignItems : " center" ,
186+ justifyContent : " center" ,
187+ transform : " translateY(-0.5px)" ,
188+ flex : " 0 0 auto"
210189 } } >
211190 { icon }
212191 </ span >
213192 < span
214193 style = { {
215- display : ' inline-block' ,
216- maxWidth : ' 100%' ,
217- overflow : ' hidden' ,
218- textOverflow : ' ellipsis' ,
194+ display : " inline-block" ,
195+ maxWidth : " 100%" ,
196+ overflow : " hidden" ,
197+ textOverflow : " ellipsis" ,
219198 } }
220199 title = { rawName }
221200 >
@@ -249,18 +228,7 @@ const customPathFunc = (linkData: any, orientation: 'vertical' | 'horizontal') =
249228 return `M ${ srcX } ${ srcY } L ${ srcX } ${ midY } L ${ tgtX } ${ midY } L ${ tgtX } ${ tgtY } ` ;
250229} ;
251230
252- // Type definition
253- interface TreeNodeDatum {
254- name : string ;
255- type ?: string ;
256- color ?: string ;
257- count ?: string ;
258- children ?: TreeNodeDatum [ ] ;
259- depth ?: number ;
260- attributes ?: { toolType ?: string } ;
261- }
262-
263- declare module 'react-d3-tree' ;
231+ declare module "react-d3-tree"
264232
265233export default function AgentCallRelationshipModal ( {
266234 visible,
@@ -297,36 +265,36 @@ export default function AgentCallRelationshipModal({
297265 if ( result . success ) {
298266 setRelationshipData ( result . data )
299267 } else {
300- message . error ( result . message || ' Failed to fetch call relationship' )
268+ message . error ( result . message || " Failed to fetch call relationship" )
301269 }
302270 } catch ( error ) {
303- console . error ( ' Failed to fetch Agent call relationship:' , error )
304- message . error ( ' Failed to fetch Agent call relationship, please try again later' )
271+ console . error ( " Failed to fetch Agent call relationship:" , error )
272+ message . error ( " Failed to fetch Agent call relationship, please try again later" )
305273 } finally {
306274 setLoading ( false )
307275 }
308276 }
309277
310278 // Generate tree data (using recursive method)
311- const generateTreeData = useCallback ( ( data : AgentCallRelationship ) : TreeNodeDatum => {
279+ const generateTreeData = useCallback ( ( data : AgentCallRelationship ) : AgentCallRelationshipTreeNodeDatum => {
312280 const centerX = 600 ;
313281 const startY = 50 ;
314282 const levelHeight = 160 ;
315283 const agentSpacing = 240 ;
316284 const toolSpacing = 160 ;
317285
318286 // Recursively generate child nodes
319- const generateSubNodes = ( subAgents : SubAgent [ ] , depth : number , parentX : number , parentY : number ) : TreeNodeDatum [ ] => {
287+ const generateSubNodes = ( subAgents : AgentCallRelationshipSubAgent [ ] , depth : number , parentX : number , parentY : number ) : AgentCallRelationshipTreeNodeDatum [ ] => {
320288
321289 return subAgents . map ( ( subAgent , index ) => {
322290 const x = parentX + ( index - ( subAgents . length - 1 ) / 2 ) * agentSpacing ;
323291 const y = parentY + levelHeight ;
324292
325- const subAgentNode : TreeNodeDatum = {
293+ const subAgentNode : AgentCallRelationshipTreeNodeDatum = {
326294 name : subAgent . name ,
327- type : ' sub' ,
295+ type : " sub" ,
328296 depth : subAgent . depth || depth ,
329- color : getNodeColor ( ' sub' , subAgent . depth || depth ) ,
297+ color : getNodeColor ( " sub" , subAgent . depth || depth ) ,
330298 children : [ ]
331299 } ;
332300
@@ -343,9 +311,9 @@ export default function AgentCallRelationshipModal({
343311
344312 subAgentNode . children ! . push ( {
345313 name : tool . name ,
346- type : ' tool' ,
314+ type : " tool" ,
347315 depth : ( subAgent . depth || depth ) + 1 ,
348- color : getNodeColor ( ' tool' , ( subAgent . depth || depth ) + 1 ) ,
316+ color : getNodeColor ( " tool" , ( subAgent . depth || depth ) + 1 ) ,
349317 attributes : { toolType : tool . type } ,
350318 children : [ ]
351319 } ) ;
@@ -362,11 +330,11 @@ export default function AgentCallRelationshipModal({
362330 } ) ;
363331 } ;
364332
365- const treeData : TreeNodeDatum = {
333+ const treeData : AgentCallRelationshipTreeNodeDatum = {
366334 name : data . name ,
367- type : ' main' ,
335+ type : " main" ,
368336 depth : 0 ,
369- color : getNodeColor ( ' main' , 0 ) ,
337+ color : getNodeColor ( " main" , 0 ) ,
370338 children : [ ]
371339 } ;
372340
@@ -383,9 +351,9 @@ export default function AgentCallRelationshipModal({
383351
384352 treeData . children ! . push ( {
385353 name : tool . name ,
386- type : ' tool' ,
354+ type : " tool" ,
387355 depth : 1 ,
388- color : getNodeColor ( ' tool' , 1 ) ,
356+ color : getNodeColor ( " tool" , 1 ) ,
389357 attributes : { toolType : tool . type } ,
390358 children : [ ]
391359 } ) ;
@@ -405,9 +373,9 @@ export default function AgentCallRelationshipModal({
405373 < >
406374 < Modal
407375 title = {
408- < div style = { { display : ' flex' , alignItems : ' center' , gap : ' 8px' } } >
409- < span > { t ( ' agentCallRelationship.title' ) } </ span >
410- < Text type = "secondary" style = { { fontSize : ' 14px' , fontWeight : ' normal' } } >
376+ < div style = { { display : " flex" , alignItems : " center" , gap : " 8px" } } >
377+ < span > { t ( " agentCallRelationship.title" ) } </ span >
378+ < Text type = "secondary" style = { { fontSize : " 14px" , fontWeight : " normal" } } >
411379 { agentName }
412380 </ Text >
413381 </ div >
@@ -421,43 +389,43 @@ export default function AgentCallRelationshipModal({
421389 style = { { top : 20 } }
422390 >
423391 { loading ? (
424- < div style = { { textAlign : ' center' , padding : ' 40px' } } >
392+ < div style = { { textAlign : " center" , padding : " 40px" } } >
425393 < Spin size = "large" />
426- < div style = { { marginTop : ' 16px' } } >
427- < Text type = "secondary" > { t ( ' agentCallRelationship.loading' ) } </ Text >
394+ < div style = { { marginTop : " 16px" } } >
395+ < Text type = "secondary" > { t ( " agentCallRelationship.loading" ) } </ Text >
428396 </ div >
429397 </ div >
430398 ) : relationshipData ? (
431399 < div >
432- < div style = { { marginBottom : ' 16px' } } >
400+ < div style = { { marginBottom : " 16px" } } >
433401 < Text type = "secondary" >
434- { t ( ' agentCallRelationship.description' , { name : relationshipData . name } ) }
402+ { t ( " agentCallRelationship.description" , { name : relationshipData . name } ) }
435403 </ Text >
436404 </ div >
437405 < div
438406 ref = { treeWrapRef }
439407 style = { {
440- height : ' 820px' ,
441- width : ' 100%' ,
442- background : ' linear-gradient(135deg, #f8fafc 0%, #e2e8f0 50%, #cbd5e1 100%)' ,
408+ height : " 820px" ,
409+ width : " 100%" ,
410+ background : " linear-gradient(135deg, #f8fafc 0%, #e2e8f0 50%, #cbd5e1 100%)" ,
443411 borderRadius : 20 ,
444- overflow : ' hidden' ,
412+ overflow : " hidden" ,
445413 padding : 0 ,
446- boxShadow : ' 0 20px 60px rgba(0,0,0,0.15), 0 8px 25px rgba(0,0,0,0.1)' ,
447- position : ' relative'
414+ boxShadow : " 0 20px 60px rgba(0,0,0,0.15), 0 8px 25px rgba(0,0,0,0.1)" ,
415+ position : " relative"
448416 } }
449417 >
450418 < Tree
451419 data = { generateTreeData ( relationshipData ) }
452420 orientation = "vertical"
453421 /** Custom path: lines end at node edges, no longer insert into interior */
454- pathFunc = { ( linkData : any ) => customPathFunc ( linkData , ' vertical' ) }
422+ pathFunc = { ( linkData : any ) => customPathFunc ( linkData , " vertical" ) }
455423 translate = { translate }
456424 renderCustomNodeElement = { CustomNode }
457425 depthFactor = { TREE_DEPTH_FACTOR }
458426 separation = { { siblings : TREE_SEP_SIB , nonSiblings : TREE_SEP_NON } }
459427 nodeSize = { { x : NODE_W , y : NODE_H } }
460- pathClassFunc = { ( ) => ' connection' }
428+ pathClassFunc = { ( ) => " connection" }
461429 zoomable = { true }
462430 scaleExtent = { { min : 0.8 , max : 1.4 } }
463431 collapsible = { false }
@@ -468,8 +436,8 @@ export default function AgentCallRelationshipModal({
468436 </ div >
469437 </ div >
470438 ) : (
471- < div style = { { textAlign : ' center' , padding : ' 40px' } } >
472- < Text type = "secondary" > { t ( ' agentCallRelationship.noData' ) } </ Text >
439+ < div style = { { textAlign : " center" , padding : " 40px" } } >
440+ < Text type = "secondary" > { t ( " agentCallRelationship.noData" ) } </ Text >
473441 </ div >
474442 ) }
475443 </ Modal >
0 commit comments