1- import { InformationCircleIcon } from "@heroicons/react/24/outline" ;
1+ import {
2+ ChevronRightIcon ,
3+ InformationCircleIcon ,
4+ } from "@heroicons/react/24/outline" ;
25import { Tool } from "core" ;
3- import { useEffect } from "react" ;
6+ import { useEffect , useMemo , useState } from "react" ;
47import { useDispatch } from "react-redux" ;
58import { useAppSelector } from "../../../../../redux/hooks" ;
69import {
@@ -21,81 +24,134 @@ function ToolPolicyItem(props: ToolDropdownItemProps) {
2124 const policy = useAppSelector (
2225 ( state ) => state . ui . toolSettings [ props . tool . function . name ] ,
2326 ) ;
27+ const [ isExpanded , setIsExpanded ] = useState ( false ) ;
2428
2529 useEffect ( ( ) => {
2630 if ( ! policy ) {
2731 dispatch ( addTool ( props . tool ) ) ;
2832 }
2933 } , [ props . tool . function . name , policy ] ) ;
3034
35+ const parameters = useMemo ( ( ) => {
36+ if ( props . tool . function . parameters ?. properties ) {
37+ return Object . entries ( props . tool . function . parameters . properties ) . map (
38+ ( [ name , schema ] ) =>
39+ [ name , schema ] as [ string , { description : string ; type : string } ] ,
40+ ) ;
41+ }
42+ return undefined ;
43+ } , [ props . tool . function . parameters ] ) ;
44+
3145 if ( ! policy ) {
3246 return null ;
3347 }
3448
3549 return (
36- < div
37- className = "hover:bg-list-active hover:text-list-active-foreground -mx-2 flex cursor-pointer items-center justify-between gap-2 rounded-md px-2 py-0.5"
38- style = { {
39- fontSize : fontSize ( - 3 ) ,
40- } }
41- data-testid = { `tool-policy-item-${ props . tool . function . name } ` }
42- onClick = { ( e ) => {
43- dispatch ( toggleToolSetting ( props . tool . function . name ) ) ;
44- e . stopPropagation ( ) ;
45- e . preventDefault ( ) ;
46- } }
47- >
48- < div className = "flex flex-1 flex-row items-center gap-1" >
49- { props . duplicatesDetected ? (
50- < >
51- < div >
52- < InformationCircleIcon
53- data-tooltip-id = { props . tool . displayTitle + "-duplicate-warning" }
54- className = "h-3 w-3 cursor-help text-yellow-500"
50+ < div className = "flex flex-col" >
51+ < div className = "flex flex-row items-center" >
52+ < div
53+ className = { `hover:bg-list-active hover:text-list-active-foreground xs:gap-1.5 flex flex-1 cursor-pointer flex-row items-center gap-1 py-0.5 pl-1 pr-2` }
54+ onClick = { ( ) => setIsExpanded ( ( val ) => ! val ) }
55+ >
56+ < ChevronRightIcon
57+ className = { `xs:flex hidden h-3 w-3 flex-shrink-0 transition-all duration-200 ${ isExpanded ? "rotate-90" : "" } ` }
58+ />
59+
60+ < div
61+ className = { `flex items-center gap-1 rounded-md` }
62+ style = { {
63+ fontSize : fontSize ( - 3 ) ,
64+ } }
65+ >
66+ { props . duplicatesDetected ? (
67+ < >
68+ < InformationCircleIcon
69+ data-tooltip-id = {
70+ props . tool . displayTitle + "-duplicate-warning"
71+ }
72+ className = "h-3 w-3 flex-shrink-0 cursor-help text-yellow-500"
73+ />
74+ < ToolTip
75+ id = { props . tool . displayTitle + "-duplicate-warning" }
76+ place = "bottom"
77+ className = "flex flex-wrap items-center"
78+ >
79+ < p className = "m-0 p-0" >
80+ < span > Duplicate tool name</ span > { " " }
81+ < code > { props . tool . function . name } </ code > { " " }
82+ < span >
83+ detected. Permissions will conflict and usage may be
84+ unpredictable
85+ </ span >
86+ </ p >
87+ </ ToolTip >
88+ </ >
89+ ) : null }
90+ { props . tool . faviconUrl && (
91+ < img
92+ src = { props . tool . faviconUrl }
93+ alt = { props . tool . displayTitle }
94+ className = "h-3 w-3 flex-shrink-0"
5595 />
56- </ div >
57- < ToolTip
58- id = { props . tool . displayTitle + "-duplicate-warning" }
59- place = "bottom"
60- className = "flex flex-wrap items-center"
61- >
62- < p className = "m-0 p-0" >
63- < span > Duplicate tool name</ span > { " " }
64- < code > { props . tool . function . name } </ code > { " " }
65- < span >
66- detected. Permissions will conflict and usage may be
67- unpredictable
68- </ span >
69- </ p >
70- </ ToolTip >
96+ ) }
97+ < span className = "line-clamp-1 break-all text-xs" >
98+ { props . tool . function . name }
99+ </ span >
100+ </ div >
101+ </ div >
102+ < div
103+ className = { `flex w-8 flex-row items-center justify-end gap-2 px-2 py-0.5 sm:w-16 ${ props . excluded ? "cursor-not-allowed" : "hover:bg-list-active hover:text-list-active-foreground cursor-pointer" } ` }
104+ data-testid = { `tool-policy-item-${ props . tool . function . name } ` }
105+ onClick = { ( e ) => {
106+ dispatch ( toggleToolSetting ( props . tool . function . name ) ) ;
107+ e . stopPropagation ( ) ;
108+ e . preventDefault ( ) ;
109+ } }
110+ >
111+ { props . excluded || policy === "disabled" ? (
112+ < >
113+ < span className = "text-lightgray sm:hidden" > Off</ span >
114+ < span className = "text-lightgray hidden sm:inline-block" >
115+ Excluded
116+ </ span >
117+ </ >
118+ ) : policy === "allowedWithoutPermission" ? (
119+ < >
120+ < span className = "text-green-500 sm:hidden" > Auto</ span >
121+ < span className = "hidden text-green-500 sm:inline-block" >
122+ Automatic
123+ </ span >
124+ </ >
125+ ) : (
126+ // allowedWithPermission
127+ < >
128+ < span className = "text-yellow-500 sm:hidden" > Ask</ span >
129+ < span className = "hidden text-yellow-500 sm:inline-block" >
130+ Ask First
131+ </ span >
132+ </ >
133+ ) }
134+ </ div >
135+ </ div >
136+ < div
137+ className = { `flex flex-col overflow-hidden ${ isExpanded ? "h-min" : "h-0 opacity-0" } gap-x-1 gap-y-2 pl-2 transition-all` }
138+ >
139+ < span className = "mt-1.5 text-xs font-bold" > Description:</ span >
140+ < span className = "italic" > { props . tool . function . description } </ span >
141+ { parameters ? (
142+ < >
143+ < span className = "text-xs font-bold" > Arguments:</ span >
144+ { parameters . map ( ( param ) => (
145+ < div className = "block" >
146+ < code className = "" > { param [ 0 ] } </ code >
147+ < span className = "ml-1" > { `(${ param [ 1 ] . type } ):` } </ span >
148+ < span className = "ml-1 italic" > { param [ 1 ] . description } </ span >
149+ </ div >
150+ ) ) }
71151 </ >
72152 ) : null }
73- < span className = "line-clamp-1 flex items-center gap-1" >
74- { props . tool . faviconUrl && (
75- < img
76- src = { props . tool . faviconUrl }
77- alt = { props . tool . displayTitle }
78- className = "h-4 w-4"
79- />
80- ) }
81- < pre className = "my-0.5 text-[11px]" > { props . tool . function . name } </ pre >
82- </ span >
153+ < div className = "h-1" > </ div >
83154 </ div >
84- { props . excluded ? (
85- < span className = "text-lightgray" > Excluded</ span >
86- ) : (
87- < div className = "flex cursor-pointer gap-2" >
88- { ( policy === "allowedWithPermission" || policy === undefined ) && (
89- < span className = "text-yellow-500" > Ask First</ span >
90- ) }
91- { policy === "allowedWithoutPermission" && (
92- < span className = "text-green-500" > Automatic</ span >
93- ) }
94- { policy === "disabled" && (
95- < span className = "text-lightgray" > Excluded</ span >
96- ) }
97- </ div >
98- ) }
99155 </ div >
100156 ) ;
101157}
0 commit comments