@@ -7,12 +7,10 @@ import {
77 Box ,
88 IconButton ,
99 Tooltip ,
10- Chip ,
1110} from "@mui/material" ;
1211import { OpenInNew , Refresh , Edit } from "@mui/icons-material" ;
1312import { useSelector } from "react-redux" ;
1413import { getConnectionSettingsState } from "../state/slices/ConnectionSettingsSlice" ;
15- import { testNotebookUrl } from "../utils/notebookValidator" ;
1614
1715const JupyterExecutor = ( ) => {
1816 // Get connection settings from Redux
@@ -22,27 +20,8 @@ const JupyterExecutor = () => {
2220 const [ jupyterUrl , setJupyterUrl ] = useState ( null ) ;
2321 const [ editableUrl , setEditableUrl ] = useState ( "" ) ;
2422 const [ isEditing , setIsEditing ] = useState ( false ) ;
25- const [ urlStatus , setUrlStatus ] = useState ( { proxied : null , direct : null } ) ;
2623 const [ iframeKey , setIframeKey ] = useState ( 0 ) ;
2724
28- // Test if a URL is accessible
29- const testUrl = async ( url ) => {
30- try {
31- console . log ( `Testing URL: ${ url } ` ) ;
32- // the response is not used here because testNotebookUrl handles it
33- const controller = new AbortController ( ) ;
34- const timeoutId = setTimeout ( ( ) => controller . abort ( ) , 3000 ) ;
35-
36- const isValid = await testNotebookUrl ( url ) ;
37- console . log ( `URL ${ url } - Notebook valid: ${ isValid } ` ) ;
38- clearTimeout ( timeoutId ) ;
39- return isValid ;
40- } catch ( error ) {
41- console . error ( `URL ${ url } - Error:` , error ) ;
42- return false ;
43- }
44- } ;
45-
4625 useEffect ( ( ) => {
4726 const fetchNotebookUrl = async ( ) => {
4827 try {
@@ -55,43 +34,14 @@ const JupyterExecutor = () => {
5534 // Extract the path from the notebook URL
5635 const urlObj = new URL ( notebookUrl ) ;
5736 const jupyterPath = urlObj . pathname ; // e.g., /jupyter/
58- const jupyterPort = urlObj . port ; // e.g., 8888
59-
6037 // Construct both possible URLs:
6138 // 1. Proxied URL through the ImSwitch API server (Caddy reverse proxy in Docker) e.g. http://localhost:80/jupyter/
6239 const proxiedUrl = `${ hostIP } :${ hostPort } ${ jupyterPath } ` ;
6340
64- // 2. Direct URL to Jupyter server (for local development) e.g. http://localhost:8888/jupyter/
65- const directUrl = `${ hostIP } :${ jupyterPort } ${ jupyterPath } ` ;
66-
67- // Test both URLs to see which one works
68- console . log ( "Testing Jupyter URLs..." ) ;
69- console . log ( "Proxied URL:" , proxiedUrl ) ;
70- console . log ( "Direct URL:" , directUrl ) ;
71-
72- const [ proxiedWorks , directWorks ] = await Promise . all ( [
73- testUrl ( proxiedUrl ) ,
74- testUrl ( directUrl ) ,
75- ] ) ;
76-
77- setUrlStatus ( { proxied : proxiedWorks , direct : directWorks } ) ;
78-
79- // Prefer proxied URL if it works, otherwise use direct URL
80- let finalUrl ;
81- if ( proxiedWorks ) {
82- finalUrl = proxiedUrl ;
83- console . log ( "✓ Using proxied Jupyter URL:" , proxiedUrl ) ;
84- } else if ( directWorks ) {
85- finalUrl = directUrl ;
86- console . log ( "✓ Using direct Jupyter URL:" , directUrl ) ;
87- } else {
88- // If neither works, default to direct URL and let user adjust
89- finalUrl = directUrl ;
90- console . warn ( "⚠ Neither URL responded, defaulting to:" , directUrl ) ;
91- }
92-
93- setJupyterUrl ( finalUrl ) ;
94- setEditableUrl ( finalUrl ) ;
41+ console . log ( "Using proxied Jupyter URL:" , proxiedUrl ) ;
42+
43+ setJupyterUrl ( proxiedUrl ) ;
44+ setEditableUrl ( proxiedUrl ) ;
9545 } catch ( error ) {
9646 console . error ( "Error fetching Jupyter URL:" , error ) ;
9747 }
@@ -121,36 +71,14 @@ const JupyterExecutor = () => {
12171 } ;
12272
12373 return (
124- < >
74+ < Box sx = { { display : "flex" , flexDirection : "column" , height : "100%" } } >
12575 { /* Top-Bar with URL editor and controls */ }
126- < AppBar position = "static" >
76+ < AppBar position = "static" sx = { { flex : "0 0 auto" } } >
12777 < Toolbar >
12878 < Typography variant = "h6" sx = { { flexGrow : 0 , marginRight : 2 } } >
12979 Jupyter Executor
13080 </ Typography >
13181
132- { /* URL Status Indicators */ }
133- { urlStatus . proxied !== null && (
134- < Tooltip title = "Proxied URL (through ImSwitch)" >
135- < Chip
136- label = "Proxied"
137- size = "small"
138- color = { urlStatus . proxied ? "success" : "default" }
139- sx = { { marginRight : 1 } }
140- />
141- </ Tooltip >
142- ) }
143- { urlStatus . direct !== null && (
144- < Tooltip title = "Direct URL (to Jupyter port)" >
145- < Chip
146- label = "Direct"
147- size = "small"
148- color = { urlStatus . direct ? "success" : "default" }
149- sx = { { marginRight : 2 } }
150- />
151- </ Tooltip >
152- ) }
153-
15482 { /* Editable URL field */ }
15583 < Box sx = { { flexGrow : 1 , display : "flex" , alignItems : "center" } } >
15684 { isEditing ? (
@@ -219,19 +147,21 @@ const JupyterExecutor = () => {
219147 </ AppBar >
220148
221149 { /* Notebook (iframe) */ }
222- < div
223- style = { {
224- width : "100%" ,
225- height : "calc(100vh - 64px)" ,
226- position : "relative" ,
227- } }
228- >
150+ < Box sx = { { width : "100%" , flex : "1 1 auto" , minHeight : 0 } } >
229151 { jupyterUrl ? (
230152 < iframe
231153 key = { iframeKey }
232154 src = { jupyterUrl }
233- style = { { width : "100%" , height : "100%" , border : "none" } }
155+ style = { {
156+ width : "100%" ,
157+ height : "100%" ,
158+ display : "block" ,
159+ boxSizing : "border-box" ,
160+ backgroundColor : "white" ,
161+ } }
234162 title = "Jupyter Notebook"
163+ onLoad = { ( ) => console . log ( "iframe loaded successfully" ) }
164+ onError = { ( e ) => console . error ( "iframe load error:" , e ) }
235165 />
236166 ) : (
237167 < Box
@@ -247,8 +177,8 @@ const JupyterExecutor = () => {
247177 Loading Jupyter Notebook...
248178 </ Box >
249179 ) }
250- </ div >
251- </ >
180+ </ Box >
181+ </ Box >
252182 ) ;
253183} ;
254184
0 commit comments