wxGUI: Initial support for Jupyter-based workflows #5901
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This pull request introduces support for running Jupyter notebooks directly within the GUI. The key benefit is the ability to use pre-configured notebooks, allowing users to start working in a Jupyter environment immediately with minimal setup. It assumes the user has the Jupyter Notebook Python package installed and available in their system.
Welcome to GRASS Jupyter environment

Implementation Overview
python/grass/workflows/
directory.py
Contains the JupyterDirectoryManager class, which manages Jupyter notebooks linked to the current mapset.
Responsibilities include mainly: Import/export of .ipynb files and managing notebook templates (welcome.ipynb, new.ipynb).
server.py
Provides two key classes: JupyterServerInstance which handles the lifecycle of an individual Jupyter server instance—installation check, port management, startup, shutdown, URL generation, etc. Also handles cleanup using atexit and signal handling to ensure servers are terminated when GRASS exits via GUI, exit, CTRL+C, or kill PID. Further, JupyterServerRegistry—a singleton that registers all active Jupyter server instances. It allows the global shutdown of all running servers when GRASS is closed from the GUI.
template_notebooks/
welcome.ipynb: A welcome notebook created on first server startup in a working directory
new.ipynb: A template used when the user creates a new notebook via GUI
gui/wxpython/jupyter_notebook/
panel.py - defines the JupyterPanel class, which creates the interactive panel inside the GUI. It includes: A toolbar and an AuiNotebook widget that lists and displays .ipynb files from the working directory
notebook.py
Class JupyterAuiNotebook—Handles logic for adding AUI notebook tabs with JavaScript injection for hiding the Jupyter File menu and header.
toolbars.py

Class JupyterToolbar—Implements the toolbar controls for notebook actions: Create new notebook, Import notebook, Export notebook, Dock/Undock, Quit
New icons order in Main window tab

Icons are newly grouped based on the Worflow character:
Additional Notes
- Multiple Jupyter servers can run in a single GRASS session (one per panel)
- All servers are automatically stopped when the GUI is closed or the session ends, even forcefully
- If no notebook is present in the working directory, a default welcome notebook is shown
- Notebooks are pre-initialized with GRASS Jupyter environment and required imports for immediate use
Working Directory - Topic for discussion
A running Jupyter server requires a working directory. Currently, the server starts in the active mapset directory, where a notebooks subdirectory is automatically created. This approach is the simplest to implement, as the session mapset directory is always available and writable.
However, from a conceptual point, it's not ideal—grassdata dir is intended for spatial data, not for workflows. In the future, I would suggest introducing a default workflow directory such as ~/grass-workflows, which would host user notebooks independently of grassdata. This concept could be expanded with a Workflows panel offering simple view and management functionality of added workflow directories. The idea is further outlined in this presentation and I am going to set up the Discussion via Discussions on GitHub.
Following steps