-
Notifications
You must be signed in to change notification settings - Fork 147
feat(python-notebook-migration): add JupyterLab docker for notebook migration tool #5256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
67e5a82
e118ca4
52c4df2
ca80390
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # Licensed to the Apache Software Foundation (ASF) under one | ||
| # or more contributor license agreements. See the NOTICE file | ||
| # distributed with this work for additional information | ||
| # regarding copyright ownership. The ASF licenses this file | ||
| # to you under the Apache License, Version 2.0 (the | ||
| # "License"); you may not use this file except in compliance | ||
| # with the License. You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, | ||
| # software distributed under the License is distributed on an | ||
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| # KIND, either express or implied. See the License for the | ||
| # specific language governing permissions and limitations | ||
| # under the License. | ||
|
|
||
| FROM jupyter/base-notebook:notebook-6.5.4 | ||
|
|
||
| # Copy custom JavaScript for Jupyter | ||
| COPY custom.js /home/jovyan/.jupyter/custom/custom.js | ||
|
|
||
| # Ensure correct permissions | ||
| USER root | ||
| RUN mkdir -p /home/jovyan/.jupyter/custom && \ | ||
| chown -R jovyan:users /home/jovyan/.jupyter | ||
|
|
||
| USER jovyan |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| /** | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| // Use Jupyter's event system to ensure the notebook is fully loaded | ||
| require(["base/js/events"], function (events) { | ||
| events.on("kernel_ready.Kernel", function () { | ||
|
|
||
| // Attach click event listener to cells | ||
| $("#notebook-container").on("click", ".cell", function (event) { | ||
| const cell = $(this); | ||
| const index = $(".cell").index(cell); | ||
| const cellContent = cell.find(".input_area").text(); | ||
|
|
||
| // Get the UUID from the cell's metadata, or use "N/A" if it doesn't exist | ||
| const cellUUID = Jupyter.notebook.get_cell(index).metadata.uuid || 'N/A'; | ||
|
|
||
| // Send a message to the parent window (Texera app) | ||
| window.parent.postMessage( | ||
| { action: "cellClicked", cellIndex: index, cellContent: cellContent, cellUUID: cellUUID }, | ||
| "http://localhost:4200" | ||
| ); | ||
| }); | ||
|
Comment on lines
+22
to
+38
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| }); | ||
| }); | ||
|
|
||
| // Listen for messages from the Texera app (or parent window) | ||
| window.addEventListener("message", function (event) { | ||
| // Verify the message origin | ||
| if (event.origin !== 'http://localhost:4200') { | ||
| console.warn("Message received from unrecognized origin:", event.origin); | ||
| return; | ||
| } | ||
|
|
||
| if (event.data.action === "triggerCellClick") { | ||
| const operatorCellUUIDs = event.data.operators || []; | ||
|
|
||
| if (!operatorCellUUIDs.length) { | ||
| console.error("No valid operator UUIDs provided in the message."); | ||
| return; // Exit if no UUIDs are provided | ||
| } | ||
|
|
||
| operatorCellUUIDs.forEach((cellUUID) => { | ||
| // Search for the cell by UUID | ||
| const allCells = Jupyter.notebook.get_cells(); | ||
| const targetCell = allCells.find((cell) => cell.metadata.uuid === cellUUID); | ||
|
|
||
| if (targetCell) { | ||
| const cellIndex = Jupyter.notebook.find_cell_index(targetCell); | ||
|
|
||
| // Scroll to and highlight the cell | ||
| let cell = document.querySelectorAll(".cell")[cellIndex]; | ||
| if (cell) { | ||
| cell.scrollIntoView({ behavior: 'smooth', block: 'center' }); | ||
| cell.classList.add("highlighted"); | ||
|
|
||
| // Remove the highlight after 3 seconds | ||
| setTimeout(() => { | ||
| cell.classList.remove("highlighted"); | ||
| }, 3000); | ||
| } else { | ||
| console.error(`Cell not found in the DOM for index ${cellIndex}.`); | ||
| } | ||
| } else { | ||
| console.error(`No cell found with UUID: ${cellUUID}`); | ||
| } | ||
| }); | ||
| } else { | ||
| console.warn("Received unknown action:", event.data.action); | ||
| } | ||
| }, false); | ||
|
|
||
| // Add custom CSS for highlighted cells | ||
| const style = document.createElement('style'); | ||
| style.innerHTML = ` | ||
| .cell.highlighted { | ||
| background-color: lightyellow; | ||
| } | ||
| `; | ||
| document.head.appendChild(style); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # Licensed to the Apache Software Foundation (ASF) under one | ||
| # or more contributor license agreements. See the NOTICE file | ||
| # distributed with this work for additional information | ||
| # regarding copyright ownership. The ASF licenses this file | ||
| # to you under the Apache License, Version 2.0 (the | ||
| # "License"); you may not use this file except in compliance | ||
| # with the License. You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, | ||
| # software distributed under the License is distributed on an | ||
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| # KIND, either express or implied. See the License for the | ||
| # specific language governing permissions and limitations | ||
| # under the License. | ||
|
|
||
| name: texera-jupyter | ||
| services: | ||
|
|
||
| jupyter: | ||
| build: | ||
| context: . | ||
| dockerfile: Dockerfile | ||
| container_name: texera-jupyter | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consistency nit: |
||
| ports: | ||
| - "9100:8888" | ||
| command: > | ||
| start-notebook.sh | ||
| --NotebookApp.token='' | ||
| --NotebookApp.password='' | ||
| --NotebookApp.disable_check_xsrf=True | ||
|
Comment on lines
+30
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The other dev-infra docker-composes in this repo (e.g., |
||
| --NotebookApp.tornado_settings="{'headers': {'Content-Security-Policy': 'frame-ancestors http://localhost:*'}}" | ||
| --NotebookApp.default_url=/tree | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Texera origin is hardcoded to
http://localhost:4200in two places (here forpostMessagetargetOrigin, and at line 45 for the inbound origin check). Same for the CSPframe-ancestors http://localhost:*indocker-compose.yml. This is fine for local dev, but any deployment under a real hostname (staging, prod, codespaces, etc.) will silently drop both inbound and outbound iframe messages. The Texera-side handler in #5263 (JupyterPanelService.handleNotebookMessage) already verifies origin dynamically againstnotebookMigrationService.getJupyterURL()— so the parent side is config-driven, but the iframe side here is hardcoded. Worth aligning: env-var injection, build-time substitution, or templating fromdocker-compose.yml.