You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@texera.apache.org by gi...@apache.org on 2026/07/27 21:56:53 UTC
(texera) branch gh-readonly-queue/main/pr-6945-8c7089b3fa247087c40817ca55c917505313c9f3 created (now 61923c5e4f)
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a change to branch gh-readonly-queue/main/pr-6945-8c7089b3fa247087c40817ca55c917505313c9f3
in repository https://gitbox.apache.org/repos/asf/texera.git
at 61923c5e4f feat(python-notebook-migration): make embedded jupyter notebook read-only (#6945)
This branch includes the following new commits:
new 61923c5e4f feat(python-notebook-migration): make embedded jupyter notebook read-only (#6945)
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(texera) 01/01: feat(python-notebook-migration): make embedded jupyter notebook read-only (#6945)
Posted by gi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-6945-8c7089b3fa247087c40817ca55c917505313c9f3
in repository https://gitbox.apache.org/repos/asf/texera.git
commit 61923c5e4f5699ea2c3a3681c072603bc2da6bbc
Author: Ryan Zhang <97...@users.noreply.github.com>
AuthorDate: Mon Jul 27 14:55:44 2026 -0700
feat(python-notebook-migration): make embedded jupyter notebook read-only (#6945)
### What changes were proposed in this PR?
The notebook migration service generates a Jupyter notebook and embeds
it in the Texera app as a reference view of the migrated workflow. It is
meant for reading, not editing. This PR configures the embedded Jupyter
container so the notebook renders as a clean, read-only view.
Changes, all scoped to the notebook migration service container assets:
1. `custom.css` (new): hides the classic Notebook chrome (header with
logo and logout, kernel and trust indicators, the File/Edit/View menu,
and the toolbar), and fixes a second, non-functional scrollbar by making
`#site` the single scroll container.
2. `Dockerfile`: copies `custom.css` into
`/home/jovyan/.jupyter/custom/custom.css`, next to the existing
`custom.js`.
3. `custom.js`: read-only hardening. Sets every code cell's CodeMirror
editor to `readOnly: "nocursor"`, calls `keyboard_manager.disable()` so
cells cannot be edited or executed, and overrides
`MarkdownCell.prototype.unrender` so markdown cells stay rendered. The
existing click-to-highlight postMessage integration is unchanged.
This does not touch the Texera frontend or backend.
### UI Comparison
Before this PR:
<img width="787" height="684" alt="2026-07-27_13-38-52"
src="https://github.com/user-attachments/assets/65cc08bd-ffcf-4343-b245-344830b6b59c"
/>
After this PR:
<img width="787" height="684" alt="image"
src="https://github.com/user-attachments/assets/41440d7d-af4e-4212-993b-0c4b1a05ea2f"
/>
### Any related issues, documentation, discussions?
Closes #6943
Parent issue #4301
### How was this PR tested?
Tested manually by building the container and opening the embedded
notebook in the Texera app:
1. The classic Notebook chrome (header, menu, toolbar, kernel and trust
indicators) is hidden; only the notebook cells are visible.
2. Clicking into a code cell does not put it in edit mode, typing does
nothing, and cells cannot be run.
3. Double-clicking a markdown cell keeps it rendered instead of dropping
into its editable source.
4. Only one working scrollbar is present.
No automated tests were added: the change is static container assets
(CSS and client-side JS in the classic Notebook UI) with no code path
exercisable by the existing unit test suites.
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 4.8)
---
.../src/main/resources/Dockerfile | 3 +-
.../src/main/resources/custom.css | 47 ++++++++++++++++++++++
.../src/main/resources/custom.js | 33 +++++++++++++++
3 files changed, 82 insertions(+), 1 deletion(-)
diff --git a/notebook-migration-service/src/main/resources/Dockerfile b/notebook-migration-service/src/main/resources/Dockerfile
index 699b271943..bea79793f2 100644
--- a/notebook-migration-service/src/main/resources/Dockerfile
+++ b/notebook-migration-service/src/main/resources/Dockerfile
@@ -17,8 +17,9 @@
FROM jupyter/base-notebook:notebook-6.5.4
-# Copy custom JavaScript for Jupyter and the startup script
+# Copy custom JavaScript/CSS for Jupyter and the startup script
COPY custom.js /home/jovyan/.jupyter/custom/custom.js
+COPY custom.css /home/jovyan/.jupyter/custom/custom.css
COPY start-texera-jupyter.sh /usr/local/bin/start-texera-jupyter.sh
# Ensure correct permissions. custom.js must stay writable by jovyan so the
diff --git a/notebook-migration-service/src/main/resources/custom.css b/notebook-migration-service/src/main/resources/custom.css
new file mode 100644
index 0000000000..5e20e01eb2
--- /dev/null
+++ b/notebook-migration-service/src/main/resources/custom.css
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+/*
+ * The notebook is embedded in the Texera app as a read-only view of the
+ * generated workflow. Hide the classic Notebook chrome (logo/name/logout,
+ * kernel and trust indicators, the File/Edit/View menu, and the toolbar) so
+ * only the notebook cells remain.
+ */
+#header,
+#menubar-container,
+#maintoolbar-container {
+ display: none !important;
+}
+
+/* Classic Notebook scrolls inside #site, but the document also scrolls, which
+ shows a second, non-functional scrollbar. Stop the document from scrolling so
+ only #site's scrollbar remains. */
+html,
+body {
+ height: 100% !important;
+ overflow: hidden !important;
+}
+
+/* The notebook offsets #site by the (now-hidden) header height; make it fill the
+ iframe (its own overflow provides the single, working scrollbar). */
+#site {
+ top: 0 !important;
+ height: 100vh !important;
+ overflow-y: auto !important;
+}
diff --git a/notebook-migration-service/src/main/resources/custom.js b/notebook-migration-service/src/main/resources/custom.js
index 70fc4ce931..6bee424368 100644
--- a/notebook-migration-service/src/main/resources/custom.js
+++ b/notebook-migration-service/src/main/resources/custom.js
@@ -47,6 +47,39 @@ require(["base/js/events"], function (events) {
});
});
+// Read-only viewing: the embedded notebook is a reference view of the generated
+// workflow, not an editing surface. Make every code cell's editor read-only and
+// disable Jupyter's keyboard shortcuts so cells cannot be edited or executed.
+// (The chrome hidden via custom.css already removes the run/save/menu controls.)
+require(["base/js/events"], function (events) {
+ function makeReadOnly() {
+ if (!window.Jupyter || !Jupyter.notebook) {
+ return;
+ }
+ // "nocursor" also blocks focus, so a click can't put a cell into edit mode.
+ Jupyter.notebook.get_cells().forEach(function (cell) {
+ if (cell.code_mirror) {
+ cell.code_mirror.setOption("readOnly", "nocursor");
+ }
+ });
+ if (Jupyter.keyboard_manager) {
+ Jupyter.keyboard_manager.disable();
+ }
+ }
+
+ // notebook_loaded fires once cells (and their editors) exist; kernel_ready
+ // fires on every (re)start and re-applies in case the manager was re-enabled.
+ events.on("notebook_loaded.Notebook", makeReadOnly);
+ events.on("kernel_ready.Kernel", makeReadOnly);
+});
+
+// Keep markdown cells rendered: overriding unrender() stops a double-click (or
+// Enter) from dropping a markdown cell into its editable source view. The
+// prototype override applies to all existing and future markdown cells.
+require(["notebook/js/textcell"], function (textcell) {
+ textcell.MarkdownCell.prototype.unrender = function () {};
+});
+
// Listen for messages from the Texera app (or parent window)
window.addEventListener("message", function (event) {
// Verify the message origin