1- import React , { useEffect , useRef } from 'react' ;
1+ import React , { useEffect , useState , useRef } from 'react' ;
22import ReactDOM from 'react-dom' ;
33import { requestAPI } from '../server/handler' ;
44import { commandIDs } from '../components/XircuitsBodyWidget' ;
55import { startRunOutputStr } from '../components/runner/RunOutput' ;
66import '../../style/ContextMenu.css' ;
7+ import { buildLocalFilePath , fetchLibraryConfig } from '../tray_library/ComponentLibraryConfig' ;
78
89export interface TrayContextMenuProps {
9- app : any ; // Specify the correct type
10+ app : any ;
1011 x : number ;
1112 y : number ;
1213 visible : boolean ;
13- val : any ; // Type this appropriately
14+ libraryName : string ;
15+ status : string ;
16+ refreshTrigger : ( ) => void ;
1417 onClose : ( ) => void ;
1518}
1619
17- async function requestLibrary ( libraryName , endpoint ) {
18- const data = { libraryName } ;
19-
20- try {
21- return await requestAPI ( endpoint , {
22- body : JSON . stringify ( data ) ,
23- method : 'POST' ,
24- } ) ;
25- } catch ( reason ) {
26- console . error ( `Error on POST /${ endpoint } ` , data , reason ) ;
27- }
28- }
29-
30- const TrayContextMenu = ( { app, x, y, visible, val, onClose } : TrayContextMenuProps ) => {
31- // Ref for the context menu
20+ const TrayContextMenu = ( { app, x, y, visible, libraryName, status, refreshTrigger, onClose } : TrayContextMenuProps ) => {
3221 const trayContextMenuRef = useRef ( null ) ;
22+ const [ validOptions , setValidOptions ] = useState ( {
23+ showInFileBrowser : false ,
24+ showReadme : false ,
25+ showExample : false ,
26+ showPageInNewTab : false
27+ } ) ;
28+
29+ useEffect ( ( ) => {
30+ // Initialize all options as invalid
31+ setValidOptions ( {
32+ showInFileBrowser : false ,
33+ showReadme : false ,
34+ showExample : false ,
35+ showPageInNewTab : false
36+ } ) ;
37+
38+ const validateOptions = async ( ) => {
39+ try {
40+ const libraryConfig = await fetchLibraryConfig ( libraryName ) ;
41+ setValidOptions ( {
42+ showInFileBrowser : ! ! libraryConfig . local_path ,
43+ showReadme : await buildLocalFilePath ( libraryName , 'readme' ) !== null ,
44+ showExample : await buildLocalFilePath ( libraryName , 'default_example_path' ) !== null ,
45+ showPageInNewTab : ! ! libraryConfig . repository
46+ } ) ;
47+ } catch ( error ) {
48+ console . error ( 'Error validating context menu options:' , error ) ;
49+ }
50+ } ;
51+
52+ if ( visible ) {
53+ validateOptions ( ) ;
54+ }
55+ } , [ libraryName , visible ] ) ;
3356
34- // Function to check if a click is outside the context menu
3557 const handleClickOutside = ( event ) => {
3658 if ( event . target . className !== "context-menu-option" ) {
3759 onClose ( ) ;
3860 }
3961 } ;
4062
41- // Effect for handling click outside
4263 useEffect ( ( ) => {
4364 document . addEventListener ( 'click' , handleClickOutside , true ) ;
4465 return ( ) => {
4566 document . removeEventListener ( 'click' , handleClickOutside , true ) ;
4667 } ;
4768 } , [ ] ) ;
69+
4870 // Context menu action handlers
49- const handleInstall = async ( val ) => {
50- const userResponse = confirm ( " Do you want to proceed with " + val + " library installation?" ) ;
71+ const handleInstall = async ( libraryName , refreshTrigger ) => {
72+ const userResponse = confirm ( ` Do you want to proceed with ${ libraryName } library installation?` ) ;
5173 if ( userResponse ) {
5274 try {
53- const response = await requestLibrary ( val , "library/get_directory" ) ;
54- if ( response [ 'path' ] ) {
55- let code = startRunOutputStr ( )
56- code += "!pip install -r " + response [ 'path' ] + "/requirements.txt"
75+ // clone the repository
76+ const response : any = await requestAPI ( "library/fetch" , {
77+ body : JSON . stringify ( { libraryName} ) ,
78+ method : 'POST' ,
79+ } ) ;
80+
81+ if ( response . status !== 'OK' ) {
82+ throw new Error ( response . message || 'Failed to fetch the library.' ) ;
83+ }
84+
85+ const libraryConfig = await fetchLibraryConfig ( libraryName ) ;
86+ if ( libraryConfig && libraryConfig . local_path ) {
87+ let code = startRunOutputStr ( ) ;
88+ code += `!pip install -r ${ libraryConfig . local_path } /requirements.txt` ;
5789 app . commands . execute ( commandIDs . executeToOutputPanel , { code } ) ;
58- console . log ( `${ val } library sucessfully installed.` ) ;
59- } else if ( response [ 'message' ] ) {
60- alert ( response [ 'message' ] ) ;
90+ console . log ( `${ libraryName } library successfully installed.` ) ;
91+ } else {
92+ alert ( `Library configuration not found for: ${ libraryName } ` ) ;
6193 }
94+ refreshTrigger ( ) ;
6295 } catch ( error ) {
63- alert ( `Failed to install ${ val } : ` + error ) ;
96+ alert ( `Failed to install ${ libraryName } . Please check the console for more details.` ) ;
97+ console . error ( `Failed to install ${ libraryName } :` , error ) ;
6498 }
65- }
66- }
67-
68- const handleShowInFileBrowser = async ( val ) => {
99+ }
100+ } ;
101+
102+ const handleShowInFileBrowser = async ( libraryName ) => {
69103 try {
70- const response = await requestLibrary ( val , "library/get_directory" ) ;
71- if ( response [ 'path' ] ) {
72- await app . commands . execute ( 'filebrowser:go-to-path' , { path : response [ 'path' ] } ) ;
73- } else if ( response [ 'message' ] ) {
74- alert ( response [ 'message' ] ) ;
104+ const libraryConfig = await fetchLibraryConfig ( libraryName ) ;
105+
106+ if ( libraryConfig && libraryConfig . local_path ) {
107+ await app . commands . execute ( 'filebrowser:go-to-path' , { path : libraryConfig . local_path } ) ;
75108 }
76109 } catch ( error ) {
77- alert ( ' Failed to Show in File Browser: ' + error ) ;
110+ alert ( ` Failed to Show in File Browser: ${ error } ` ) ;
78111 }
79112 } ;
80-
81- const handleShowReadme = async ( val ) => {
113+
114+ const handleShowReadme = async ( libraryName ) => {
115+ try {
116+ const readmePath = await buildLocalFilePath ( libraryName , 'readme' ) ;
117+ if ( readmePath ) {
118+ await app . commands . execute ( 'markdownviewer:open' , { path : readmePath , options : { mode : 'split-right' } } ) ;
119+ }
120+ } catch ( error ) {
121+ alert ( 'Failed to Show Readme: ' + error ) ;
122+ }
123+ } ;
124+
125+ const handleShowExample = async ( libraryName ) => {
82126 try {
83- const response = await requestLibrary ( val , "library/get_readme" ) ;
84- if ( response [ 'path' ] ) {
85- await app . commands . execute ( 'markdownviewer:open' , { path : response [ 'path' ] , options : { mode : 'split-right' } } ) ;
86- } else if ( response [ 'message' ] ) {
87- alert ( response [ 'message' ] ) ;
127+ const examplePath = await buildLocalFilePath ( libraryName , 'default_example_path' ) ;
128+ if ( examplePath ) {
129+ await app . commands . execute ( 'docmanager:open' , { path : examplePath } ) ;
88130 }
89131 } catch ( error ) {
90- alert ( 'Failed to Show Readme : ' + error ) ;
132+ alert ( 'Failed to Show Example : ' + error ) ;
91133 }
92134 } ;
93135
94- const handleShowExample = async ( val ) => {
136+ const handleShowPageInNewTab = async ( libraryName ) => {
95137 try {
96- const response = await requestLibrary ( val , "library/get_example" ) ;
97- if ( response [ 'path' ] ) {
98- await app . commands . execute ( 'docmanager:open' , { path : response [ 'path' ] } ) ;
99- } else if ( response [ 'message' ] ) {
100- alert ( response [ 'message' ] ) ;
138+ const libraryConfig = await fetchLibraryConfig ( libraryName ) ;
139+
140+ if ( libraryConfig && libraryConfig . repository ) {
141+ window . open ( libraryConfig . repository , '_blank' ) ;
101142 }
102143 } catch ( error ) {
103- alert ( ' Failed to Show Example: ' + error ) ;
144+ alert ( ` Failed to Open Page: ${ error } ` ) ;
104145 }
105146 } ;
106147
@@ -110,10 +151,29 @@ const TrayContextMenu = ({ app, x, y, visible, val, onClose }: TrayContextMenuPr
110151
111152 return ReactDOM . createPortal (
112153 < div className = "context-menu" ref = { trayContextMenuRef } style = { { position : 'absolute' , left : `${ x + 5 } px` , top : `${ y } px` , zIndex : 1000 } } >
113- < div className = "context-menu-option" onClick = { ( ) => { handleInstall ( val ) ; onClose ( ) ; } } > Install</ div >
114- < div className = "context-menu-option" onClick = { ( ) => { handleShowInFileBrowser ( val ) ; onClose ( ) ; } } > Show in File Explorer</ div >
115- < div className = "context-menu-option" onClick = { ( ) => { handleShowReadme ( val ) ; onClose ( ) ; } } > See Readme</ div >
116- < div className = "context-menu-option" onClick = { ( ) => { handleShowExample ( val ) ; onClose ( ) ; } } > Show Example</ div >
154+ { status === 'remote' ? (
155+ < >
156+ < div className = "context-menu-option" onClick = { ( ) => { handleInstall ( libraryName , refreshTrigger ) ; onClose ( ) ; } } > Install</ div >
157+ { validOptions . showPageInNewTab && (
158+ < div className = "context-menu-option" onClick = { ( ) => { handleShowPageInNewTab ( libraryName ) ; onClose ( ) ; } } > Open Repository</ div >
159+ ) }
160+ </ >
161+ ) : (
162+ < >
163+ { validOptions . showInFileBrowser && (
164+ < div className = "context-menu-option" onClick = { ( ) => { handleShowInFileBrowser ( libraryName ) ; onClose ( ) ; } } > Show in File Explorer</ div >
165+ ) }
166+ { validOptions . showReadme && (
167+ < div className = "context-menu-option" onClick = { ( ) => { handleShowReadme ( libraryName ) ; onClose ( ) ; } } > See Readme</ div >
168+ ) }
169+ { validOptions . showExample && (
170+ < div className = "context-menu-option" onClick = { ( ) => { handleShowExample ( libraryName ) ; onClose ( ) ; } } > Show Example</ div >
171+ ) }
172+ { validOptions . showPageInNewTab && (
173+ < div className = "context-menu-option" onClick = { ( ) => { handleShowPageInNewTab ( libraryName ) ; onClose ( ) ; } } > Open Repository</ div >
174+ ) }
175+ </ >
176+ ) }
117177 </ div > ,
118178 document . body
119179 ) ;
0 commit comments