Skip to content

Commit 09ff8e6

Browse files
committed
Enhance JupyterNotebook integration by adjusting layout and removing unused URL testing logic
1 parent da4731c commit 09ff8e6

File tree

2 files changed

+28
-94
lines changed

2 files changed

+28
-94
lines changed

frontend/src/App.jsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ function App() {
410410
flexGrow: 1,
411411
display: "flex",
412412
position: "absolute",
413-
p: isMobile ? 1 : 3,
413+
p: selectedPlugin === "JupyterNotebook" ? 0 : isMobile ? 1 : 3,
414414
left: drawerWidth,
415415
width: "calc(100% - " + drawerWidth + "px)",
416416
height: "calc(100vh - 64px)",
@@ -421,7 +421,7 @@ function App() {
421421
duration: theme.transitions.duration.leavingScreen,
422422
}),
423423
minHeight: "calc(100vh - 64px)",
424-
overflow: "auto",
424+
overflow: selectedPlugin === "JupyterNotebook" ? "hidden" : "auto",
425425
}}
426426
>
427427
{selectedPlugin === "LiveView" && (
@@ -448,12 +448,16 @@ function App() {
448448
<StageCenterCalibrationWizard />
449449
)}
450450
{selectedPlugin === "HoloController" && <HoloController />}
451-
{selectedPlugin === "OffAxisHoloController" && <OffAxisHoloController />}
451+
{selectedPlugin === "OffAxisHoloController" && (
452+
<OffAxisHoloController />
453+
)}
452454
{selectedPlugin === "DPCController" && <DPCController />}
453455
{selectedPlugin === "JupyterNotebook" && (
454-
<JupyterProvider>
455-
<JupyterExecutor />
456-
</JupyterProvider>
456+
<Box sx={{ width: "100%", height: "100%", minHeight: 0 }}>
457+
<JupyterProvider>
458+
<JupyterExecutor />
459+
</JupyterProvider>
460+
</Box>
457461
)}
458462
{selectedPlugin === "Infinity Scanning" && <LargeFovScanController />}
459463
{selectedPlugin === "Blockly" && <BlocklyController />}

frontend/src/components/JupyterExecutor.js

Lines changed: 18 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ import {
77
Box,
88
IconButton,
99
Tooltip,
10-
Chip,
1110
} from "@mui/material";
1211
import { OpenInNew, Refresh, Edit } from "@mui/icons-material";
1312
import { useSelector } from "react-redux";
1413
import { getConnectionSettingsState } from "../state/slices/ConnectionSettingsSlice";
15-
import { testNotebookUrl } from "../utils/notebookValidator";
1614

1715
const 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

Comments
 (0)