mirror of
https://github.com/jupyter/notebook.git
synced 2025-04-06 13:50:29 +08:00
Customize the shell layout with the settings (#6921)
* Add settings file * Add support for layout customization * Fix tests * Add `type` option * Fix opening document widgets * Fix opening documents * Add defaults for Markdown Preview * Add docs * Add screenshots * Add `@jupyterlab/attachments` * Fix integrity * Add simple UI tests for layout customization * Lint * Update Playwright Snapshots * Update Playwright Snapshots * Update docs * Add missing null --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
33a383d3f8
commit
ab57fa1d20
155
app/package.json
155
app/package.json
@ -10,8 +10,8 @@
|
||||
"watch": "webpack --config ./webpack.config.watch.js"
|
||||
},
|
||||
"resolutions": {
|
||||
"@codemirror/state": "~6.2.0",
|
||||
"@codemirror/view": "~6.11.0",
|
||||
"@codemirror/state": "~6.2.1",
|
||||
"@codemirror/view": "~6.13.2",
|
||||
"@jupyter-notebook/application": "~7.0.0-beta.4",
|
||||
"@jupyter-notebook/application-extension": "~7.0.0-beta.4",
|
||||
"@jupyter-notebook/console-extension": "~7.0.0-beta.4",
|
||||
@ -24,76 +24,79 @@
|
||||
"@jupyter-notebook/tree-extension": "~7.0.0-beta.4",
|
||||
"@jupyter-notebook/ui-components": "~7.0.0-beta.4",
|
||||
"@jupyter/ydoc": "~1.0.2",
|
||||
"@jupyterlab/application": "~4.0.1",
|
||||
"@jupyterlab/application-extension": "~4.0.1",
|
||||
"@jupyterlab/apputils": "~4.1.1",
|
||||
"@jupyterlab/apputils-extension": "~4.0.1",
|
||||
"@jupyterlab/cell-toolbar": "~4.0.1",
|
||||
"@jupyterlab/cell-toolbar-extension": "~4.0.1",
|
||||
"@jupyterlab/celltags-extension": "~4.0.1",
|
||||
"@jupyterlab/codeeditor": "~4.0.1",
|
||||
"@jupyterlab/codemirror": "~4.0.1",
|
||||
"@jupyterlab/codemirror-extension": "~4.0.1",
|
||||
"@jupyterlab/completer": "~4.0.1",
|
||||
"@jupyterlab/completer-extension": "~4.0.1",
|
||||
"@jupyterlab/console": "~4.0.1",
|
||||
"@jupyterlab/console-extension": "~4.0.1",
|
||||
"@jupyterlab/coreutils": "~6.0.1",
|
||||
"@jupyterlab/csvviewer-extension": "~4.0.1",
|
||||
"@jupyterlab/debugger": "~4.0.1",
|
||||
"@jupyterlab/debugger-extension": "~4.0.1",
|
||||
"@jupyterlab/docmanager": "~4.0.1",
|
||||
"@jupyterlab/docmanager-extension": "~4.0.1",
|
||||
"@jupyterlab/documentsearch": "~4.0.1",
|
||||
"@jupyterlab/documentsearch-extension": "~4.0.1",
|
||||
"@jupyterlab/extensionmanager": "~4.0.1",
|
||||
"@jupyterlab/extensionmanager-extension": "~4.0.1",
|
||||
"@jupyterlab/filebrowser": "~4.0.1",
|
||||
"@jupyterlab/filebrowser-extension": "~4.0.1",
|
||||
"@jupyterlab/fileeditor": "~4.0.1",
|
||||
"@jupyterlab/fileeditor-extension": "~4.0.1",
|
||||
"@jupyterlab/htmlviewer": "~4.0.1",
|
||||
"@jupyterlab/htmlviewer-extension": "~4.0.1",
|
||||
"@jupyterlab/hub-extension": "~4.0.1",
|
||||
"@jupyterlab/javascript-extension": "~4.0.1",
|
||||
"@jupyterlab/json-extension": "~4.0.1",
|
||||
"@jupyterlab/lsp": "~4.0.1",
|
||||
"@jupyterlab/lsp-extension": "~4.0.1",
|
||||
"@jupyterlab/mainmenu": "~4.0.1",
|
||||
"@jupyterlab/mainmenu-extension": "~4.0.1",
|
||||
"@jupyterlab/markedparser-extension": "~4.0.1",
|
||||
"@jupyterlab/mathjax-extension": "~4.0.1",
|
||||
"@jupyterlab/metadataform": "~4.0.1",
|
||||
"@jupyterlab/metadataform-extension": "~4.0.1",
|
||||
"@jupyterlab/notebook": "~4.0.1",
|
||||
"@jupyterlab/notebook-extension": "~4.0.1",
|
||||
"@jupyterlab/observables": "~5.0.1",
|
||||
"@jupyterlab/outputarea": "~4.0.1",
|
||||
"@jupyterlab/pdf-extension": "~4.0.1",
|
||||
"@jupyterlab/rendermime": "~4.0.1",
|
||||
"@jupyterlab/rendermime-interfaces": "~3.8.1",
|
||||
"@jupyterlab/running-extension": "~4.0.1",
|
||||
"@jupyterlab/services": "~7.0.1",
|
||||
"@jupyterlab/settingeditor": "~4.0.1",
|
||||
"@jupyterlab/settingeditor-extension": "~4.0.1",
|
||||
"@jupyterlab/settingregistry": "~4.0.1",
|
||||
"@jupyterlab/shortcuts-extension": "~4.0.1",
|
||||
"@jupyterlab/statedb": "~4.0.1",
|
||||
"@jupyterlab/statusbar": "~4.0.1",
|
||||
"@jupyterlab/terminal": "~4.0.1",
|
||||
"@jupyterlab/terminal-extension": "~4.0.1",
|
||||
"@jupyterlab/theme-dark-extension": "~4.0.1",
|
||||
"@jupyterlab/theme-light-extension": "~4.0.1",
|
||||
"@jupyterlab/toc-extension": "~6.0.1",
|
||||
"@jupyterlab/tooltip": "~4.0.1",
|
||||
"@jupyterlab/tooltip-extension": "~4.0.1",
|
||||
"@jupyterlab/translation": "~4.0.1",
|
||||
"@jupyterlab/translation-extension": "~4.0.1",
|
||||
"@jupyterlab/ui-components": "~4.0.1",
|
||||
"@jupyterlab/ui-components-extension": "~4.0.1",
|
||||
"@jupyterlab/vega5-extension": "~4.0.1",
|
||||
"@lezer/common": "~1.0.2",
|
||||
"@lezer/highlight": "~1.1.4",
|
||||
"@jupyterlab/application": "~4.0.2",
|
||||
"@jupyterlab/application-extension": "~4.0.2",
|
||||
"@jupyterlab/apputils": "~4.1.2",
|
||||
"@jupyterlab/apputils-extension": "~4.0.2",
|
||||
"@jupyterlab/attachments": "~4.0.2",
|
||||
"@jupyterlab/cell-toolbar": "~4.0.2",
|
||||
"@jupyterlab/cell-toolbar-extension": "~4.0.2",
|
||||
"@jupyterlab/celltags-extension": "~4.0.2",
|
||||
"@jupyterlab/codeeditor": "~4.0.2",
|
||||
"@jupyterlab/codemirror": "~4.0.2",
|
||||
"@jupyterlab/codemirror-extension": "~4.0.2",
|
||||
"@jupyterlab/completer": "~4.0.2",
|
||||
"@jupyterlab/completer-extension": "~4.0.2",
|
||||
"@jupyterlab/console": "~4.0.2",
|
||||
"@jupyterlab/console-extension": "~4.0.2",
|
||||
"@jupyterlab/coreutils": "~6.0.2",
|
||||
"@jupyterlab/csvviewer-extension": "~4.0.2",
|
||||
"@jupyterlab/debugger": "~4.0.2",
|
||||
"@jupyterlab/debugger-extension": "~4.0.2",
|
||||
"@jupyterlab/docmanager": "~4.0.2",
|
||||
"@jupyterlab/docmanager-extension": "~4.0.2",
|
||||
"@jupyterlab/documentsearch": "~4.0.2",
|
||||
"@jupyterlab/documentsearch-extension": "~4.0.2",
|
||||
"@jupyterlab/extensionmanager": "~4.0.2",
|
||||
"@jupyterlab/extensionmanager-extension": "~4.0.2",
|
||||
"@jupyterlab/filebrowser": "~4.0.2",
|
||||
"@jupyterlab/filebrowser-extension": "~4.0.2",
|
||||
"@jupyterlab/fileeditor": "~4.0.2",
|
||||
"@jupyterlab/fileeditor-extension": "~4.0.2",
|
||||
"@jupyterlab/htmlviewer": "~4.0.2",
|
||||
"@jupyterlab/htmlviewer-extension": "~4.0.2",
|
||||
"@jupyterlab/hub-extension": "~4.0.2",
|
||||
"@jupyterlab/javascript-extension": "~4.0.2",
|
||||
"@jupyterlab/json-extension": "~4.0.2",
|
||||
"@jupyterlab/lsp": "~4.0.2",
|
||||
"@jupyterlab/lsp-extension": "~4.0.2",
|
||||
"@jupyterlab/mainmenu": "~4.0.2",
|
||||
"@jupyterlab/mainmenu-extension": "~4.0.2",
|
||||
"@jupyterlab/markdownviewer": "~4.0.2",
|
||||
"@jupyterlab/markdownviewer-extension": "~4.0.2",
|
||||
"@jupyterlab/markedparser-extension": "~4.0.2",
|
||||
"@jupyterlab/mathjax-extension": "~4.0.2",
|
||||
"@jupyterlab/metadataform": "~4.0.2",
|
||||
"@jupyterlab/metadataform-extension": "~4.0.2",
|
||||
"@jupyterlab/notebook": "~4.0.2",
|
||||
"@jupyterlab/notebook-extension": "~4.0.2",
|
||||
"@jupyterlab/observables": "~5.0.2",
|
||||
"@jupyterlab/outputarea": "~4.0.2",
|
||||
"@jupyterlab/pdf-extension": "~4.0.2",
|
||||
"@jupyterlab/rendermime": "~4.0.2",
|
||||
"@jupyterlab/rendermime-interfaces": "~3.8.2",
|
||||
"@jupyterlab/running-extension": "~4.0.2",
|
||||
"@jupyterlab/services": "~7.0.2",
|
||||
"@jupyterlab/settingeditor": "~4.0.2",
|
||||
"@jupyterlab/settingeditor-extension": "~4.0.2",
|
||||
"@jupyterlab/settingregistry": "~4.0.2",
|
||||
"@jupyterlab/shortcuts-extension": "~4.0.2",
|
||||
"@jupyterlab/statedb": "~4.0.2",
|
||||
"@jupyterlab/statusbar": "~4.0.2",
|
||||
"@jupyterlab/terminal": "~4.0.2",
|
||||
"@jupyterlab/terminal-extension": "~4.0.2",
|
||||
"@jupyterlab/theme-dark-extension": "~4.0.2",
|
||||
"@jupyterlab/theme-light-extension": "~4.0.2",
|
||||
"@jupyterlab/toc-extension": "~6.0.2",
|
||||
"@jupyterlab/tooltip": "~4.0.2",
|
||||
"@jupyterlab/tooltip-extension": "~4.0.2",
|
||||
"@jupyterlab/translation": "~4.0.2",
|
||||
"@jupyterlab/translation-extension": "~4.0.2",
|
||||
"@jupyterlab/ui-components": "~4.0.2",
|
||||
"@jupyterlab/ui-components-extension": "~4.0.2",
|
||||
"@jupyterlab/vega5-extension": "~4.0.2",
|
||||
"@lezer/common": "~1.0.3",
|
||||
"@lezer/highlight": "~1.1.6",
|
||||
"@lumino/algorithm": "~2.0.0",
|
||||
"@lumino/application": "~2.1.1",
|
||||
"@lumino/commands": "~2.1.1",
|
||||
@ -108,7 +111,7 @@
|
||||
"@lumino/widgets": "~2.1.1",
|
||||
"react": "~18.2.0",
|
||||
"react-dom": "~18.2.0",
|
||||
"yjs": "~13.6.1"
|
||||
"yjs": "~13.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jupyter-notebook/application": "^7.0.0-beta.4",
|
||||
@ -124,6 +127,7 @@
|
||||
"@jupyter-notebook/ui-components": "^7.0.0-beta.4",
|
||||
"@jupyterlab/application-extension": "^4.0.1",
|
||||
"@jupyterlab/apputils-extension": "^4.0.1",
|
||||
"@jupyterlab/attachments": "^4.0.1",
|
||||
"@jupyterlab/cell-toolbar-extension": "^4.0.1",
|
||||
"@jupyterlab/celltags-extension": "^4.0.1",
|
||||
"@jupyterlab/codemirror": "^4.0.1",
|
||||
@ -145,6 +149,7 @@
|
||||
"@jupyterlab/lsp": "^4.0.1",
|
||||
"@jupyterlab/lsp-extension": "^4.0.1",
|
||||
"@jupyterlab/mainmenu-extension": "^4.0.1",
|
||||
"@jupyterlab/markdownviewer-extension": "^4.0.1",
|
||||
"@jupyterlab/markedparser-extension": "^4.0.1",
|
||||
"@jupyterlab/mathjax-extension": "^4.0.1",
|
||||
"@jupyterlab/metadataform-extension": "^4.0.1",
|
||||
@ -322,7 +327,8 @@
|
||||
"@jupyterlab/fileeditor-extension": [
|
||||
"@jupyterlab/fileeditor-extension:completer",
|
||||
"@jupyterlab/fileeditor-extension:search"
|
||||
]
|
||||
],
|
||||
"@jupyterlab/markdownviewer-extension": true
|
||||
}
|
||||
},
|
||||
"singletonPackages": [
|
||||
@ -347,6 +353,7 @@
|
||||
"@jupyterlab/htmlviewer",
|
||||
"@jupyterlab/lsp",
|
||||
"@jupyterlab/mainmenu",
|
||||
"@jupyterlab/markdownviewer",
|
||||
"@jupyterlab/metadataform",
|
||||
"@jupyterlab/notebook",
|
||||
"@jupyterlab/observables",
|
||||
|
@ -5,7 +5,6 @@
|
||||
:maxdepth: 1
|
||||
|
||||
configuring/config_overview
|
||||
configuring/plugins
|
||||
Security <https://jupyter-server.readthedocs.io/en/stable/operators/security.html>
|
||||
extending/index.rst
|
||||
```
|
||||
|
62
docs/source/configuring/interface_customization.md
Normal file
62
docs/source/configuring/interface_customization.md
Normal file
@ -0,0 +1,62 @@
|
||||
# Interface Customization
|
||||
|
||||
Multiple elements in the Notebook interface can be customized via the Settings Editor.
|
||||
|
||||
## Layout
|
||||
|
||||
By default some widgets are displayed in pre-defined parts of the user interface, which are often called "areas" or "regions".
|
||||
For example the table of contents will be displayed in the `left` area by default, while the debugger will be displayed in the `right` area.
|
||||
|
||||
However the positioning of some of these components can also be customized via the Settings Editor. Below are a few examples of how to do this.
|
||||
|
||||
### Open the Markdown Preview on the left
|
||||
|
||||
It is often useful to be able to see a rendered preview of a Markdown document while editing it.
|
||||
|
||||
By default the Markdown Preview opens on the right side of the application. However it is also possible to open it on the left side by changing the Notebook Shell settings in the Advanced Settings Editor:
|
||||
|
||||
```json
|
||||
{
|
||||
"layout": {
|
||||
"Markdown Preview": {
|
||||
"area": "left"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Configuring a third-party widget
|
||||
|
||||
Third-party extensions can also add widgets to the application shell. This is for example the case with the [Voila extension](https://github.com/voila-dashboards/voila), which adds a preview widget to visualize a notebook as a dashboard.
|
||||
|
||||
By default in JupyterLab the Voila Preview is added to the `main` area next to the corresponding notebook. With Notebook 7 it is possible to move the Voila Preview to the `right` area by changing the Notebook Shell setting in the Advanced Settings Editor as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"layout": {
|
||||
"Voila Preview": {
|
||||
"area": "right"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
```{note}
|
||||
Refer to the [JupyterLab Layout Documentation](https://jupyterlab.readthedocs.io/en/latest/user/interface_customization.html#layout)
|
||||
to learn more about the default positioning of other UI elements.
|
||||
```
|
||||
|
||||
## Toolbars, Menu bar and Context Menu
|
||||
|
||||
It is also possible to customize toolbars, menus and context menu entries via the Settings Editor.
|
||||
|
||||
For example the items of the notebook toolbar can be reordered, or some menu entries can be hidden.
|
||||
|
||||
```{note}
|
||||
Refer to the [JupyterLab Documentation](https://jupyterlab.readthedocs.io/en/latest/user/interface_customization.html)
|
||||
to learn more about general interface customization via the settings editor.
|
||||
```
|
@ -10,6 +10,8 @@ ui_components
|
||||
notebook_7_features
|
||||
examples/Notebook/examples_index.rst
|
||||
custom_css
|
||||
configuring/plugins
|
||||
configuring/interface_customization
|
||||
troubleshooting
|
||||
changelog
|
||||
```
|
||||
|
34
packages/application-extension/schema/shell.json
Normal file
34
packages/application-extension/schema/shell.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Notebook Shell",
|
||||
"description": "Notebook Shell layout settings.",
|
||||
"properties": {
|
||||
"layout": {
|
||||
"$ref": "#/definitions/layout",
|
||||
"type": "object",
|
||||
"title": "Customize shell widget positioning",
|
||||
"description": "Overrides default widget position in the application layout",
|
||||
"default": {
|
||||
"Markdown Preview": { "area": "right" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"definitions": {
|
||||
"layout": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"[\\w-]+": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"area": {
|
||||
"enum": ["left", "right"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -384,14 +384,36 @@ const rendermime: JupyterFrontEndPlugin<IRenderMimeRegistry> = {
|
||||
*/
|
||||
const shell: JupyterFrontEndPlugin<INotebookShell> = {
|
||||
id: '@jupyter-notebook/application-extension:shell',
|
||||
activate: (app: JupyterFrontEnd) => {
|
||||
autoStart: true,
|
||||
provides: INotebookShell,
|
||||
optional: [ISettingRegistry],
|
||||
activate: (
|
||||
app: JupyterFrontEnd,
|
||||
settingRegistry: ISettingRegistry | null
|
||||
) => {
|
||||
if (!(app.shell instanceof NotebookShell)) {
|
||||
throw new Error(`${shell.id} did not find a NotebookShell instance.`);
|
||||
}
|
||||
return app.shell;
|
||||
const notebookShell = app.shell;
|
||||
|
||||
if (settingRegistry) {
|
||||
settingRegistry
|
||||
.load(shell.id)
|
||||
.then((settings) => {
|
||||
// Add a layer of customization to support app shell mode
|
||||
const customLayout = settings.composite['layout'] as any;
|
||||
|
||||
// Restore the layout.
|
||||
void notebookShell.restoreLayout(customLayout);
|
||||
})
|
||||
.catch((reason) => {
|
||||
console.error('Fail to load settings for the layout restorer.');
|
||||
console.error(reason);
|
||||
});
|
||||
}
|
||||
|
||||
return notebookShell;
|
||||
},
|
||||
autoStart: true,
|
||||
provides: INotebookShell,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -6,7 +6,7 @@ import { DocumentRegistry } from '@jupyterlab/docregistry';
|
||||
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
|
||||
|
||||
import { find } from '@lumino/algorithm';
|
||||
import { PromiseDelegate, Token } from '@lumino/coreutils';
|
||||
import { JSONExt, PromiseDelegate, Token } from '@lumino/coreutils';
|
||||
import { ISignal, Signal } from '@lumino/signaling';
|
||||
|
||||
import { BoxLayout, Panel, SplitPanel, Widget } from '@lumino/widgets';
|
||||
@ -24,6 +24,40 @@ export const INotebookShell = new Token<INotebookShell>(
|
||||
*/
|
||||
export interface INotebookShell extends NotebookShell {}
|
||||
|
||||
/**
|
||||
* The namespace for INotebookShell type information.
|
||||
*/
|
||||
export namespace INotebookShell {
|
||||
/**
|
||||
* The areas of the application shell where widgets can reside.
|
||||
*/
|
||||
export type Area = 'main' | 'top' | 'menu' | 'left' | 'right';
|
||||
|
||||
/**
|
||||
* Widget position
|
||||
*/
|
||||
export interface IWidgetPosition {
|
||||
/**
|
||||
* Widget area
|
||||
*/
|
||||
area?: Area;
|
||||
/**
|
||||
* Widget opening options
|
||||
*/
|
||||
options?: DocumentRegistry.IOpenOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping of widget type identifier and their user customized position
|
||||
*/
|
||||
export interface IUserLayout {
|
||||
/**
|
||||
* Widget customized position
|
||||
*/
|
||||
[k: string]: IWidgetPosition;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The default rank for ranked panels.
|
||||
*/
|
||||
@ -36,6 +70,7 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
|
||||
constructor() {
|
||||
super();
|
||||
this.id = 'main';
|
||||
this._userLayout = {};
|
||||
|
||||
this._topHandler = new PanelHandler();
|
||||
this._menuHandler = new PanelHandler();
|
||||
@ -211,13 +246,23 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* User custom shell layout.
|
||||
*/
|
||||
get userLayout() {
|
||||
return JSONExt.deepCopy(this._userLayout as any);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate a widget in its area.
|
||||
*/
|
||||
activateById(id: string): void {
|
||||
// Search all areas that can have widgets for this widget, starting with main.
|
||||
for (const area of ['main', 'top', 'left', 'right', 'menu']) {
|
||||
const widget = find(this.widgets(area as Shell.Area), (w) => w.id === id);
|
||||
const widget = find(
|
||||
this.widgets(area as INotebookShell.Area),
|
||||
(w) => w.id === id
|
||||
);
|
||||
if (widget) {
|
||||
if (area === 'left') {
|
||||
this.expandLeft(id);
|
||||
@ -243,9 +288,25 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
|
||||
*/
|
||||
add(
|
||||
widget: Widget,
|
||||
area?: Shell.Area,
|
||||
area?: INotebookShell.Area,
|
||||
options?: DocumentRegistry.IOpenOptions
|
||||
): void {
|
||||
let userPosition: INotebookShell.IWidgetPosition | undefined;
|
||||
if (options?.type && this._userLayout[options.type]) {
|
||||
userPosition = this._userLayout[options.type];
|
||||
} else {
|
||||
userPosition = this._userLayout[widget.id];
|
||||
}
|
||||
|
||||
area = userPosition?.area ?? area;
|
||||
options =
|
||||
options || userPosition?.options
|
||||
? {
|
||||
...options,
|
||||
...userPosition?.options,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const rank = options?.rank ?? DEFAULT_RANK;
|
||||
switch (area) {
|
||||
case 'top':
|
||||
@ -293,7 +354,7 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
|
||||
*
|
||||
* @param area The area
|
||||
*/
|
||||
*widgets(area: Shell.Area): IterableIterator<Widget> {
|
||||
*widgets(area: INotebookShell.Area): IterableIterator<Widget> {
|
||||
switch (area ?? 'main') {
|
||||
case 'top':
|
||||
yield* this._topHandler.panel.widgets;
|
||||
@ -348,6 +409,15 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
|
||||
this._rightHandler.panel.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the layout state and configuration for the application shell.
|
||||
*/
|
||||
async restoreLayout(
|
||||
configuration: INotebookShell.IUserLayout
|
||||
): Promise<void> {
|
||||
this._userLayout = configuration;
|
||||
}
|
||||
|
||||
private _topWrapper: Panel;
|
||||
private _topHandler: PanelHandler;
|
||||
private _menuWrapper: Panel;
|
||||
@ -361,16 +431,7 @@ export class NotebookShell extends Widget implements JupyterFrontEnd.IShell {
|
||||
private _translator: ITranslator = nullTranslator;
|
||||
private _currentChanged = new Signal<this, void>(this);
|
||||
private _mainWidgetLoaded = new PromiseDelegate<void>();
|
||||
}
|
||||
|
||||
/**
|
||||
* A namespace for Shell statics
|
||||
*/
|
||||
export namespace Shell {
|
||||
/**
|
||||
* The areas of the application shell where widgets can reside.
|
||||
*/
|
||||
export type Area = 'main' | 'top' | 'left' | 'right' | 'menu';
|
||||
private _userLayout: INotebookShell.IUserLayout;
|
||||
}
|
||||
|
||||
export namespace Private {
|
||||
|
@ -1,11 +1,7 @@
|
||||
// Copyright (c) Jupyter Development Team.
|
||||
// Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import {
|
||||
INotebookShell,
|
||||
NotebookShell,
|
||||
Shell,
|
||||
} from '@jupyter-notebook/application';
|
||||
import { INotebookShell, NotebookShell } from '@jupyter-notebook/application';
|
||||
|
||||
import { JupyterFrontEnd } from '@jupyterlab/application';
|
||||
|
||||
@ -30,7 +26,7 @@ describe('Shell for notebooks', () => {
|
||||
|
||||
it('should make some areas empty initially', () => {
|
||||
['main', 'left', 'right', 'menu'].forEach((area) => {
|
||||
const widgets = Array.from(shell.widgets(area as Shell.Area));
|
||||
const widgets = Array.from(shell.widgets(area as INotebookShell.Area));
|
||||
expect(widgets.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
@ -139,7 +135,7 @@ describe('Shell for tree view', () => {
|
||||
|
||||
it('should make some areas empty initially', () => {
|
||||
['main', 'left', 'right', 'menu'].forEach((area) => {
|
||||
const widgets = Array.from(shell.widgets(area as Shell.Area));
|
||||
const widgets = Array.from(shell.widgets(area as INotebookShell.Area));
|
||||
expect(widgets.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
@ -12,6 +12,8 @@ import { IDocumentWidgetOpener } from '@jupyterlab/docmanager';
|
||||
|
||||
import { IDocumentWidget, DocumentRegistry } from '@jupyterlab/docregistry';
|
||||
|
||||
import { INotebookShell } from '@jupyter-notebook/application';
|
||||
|
||||
import { Signal } from '@lumino/signaling';
|
||||
|
||||
/**
|
||||
@ -21,17 +23,20 @@ import { Signal } from '@lumino/signaling';
|
||||
const opener: JupyterFrontEndPlugin<IDocumentWidgetOpener> = {
|
||||
id: '@jupyter-notebook/docmanager-extension:opener',
|
||||
autoStart: true,
|
||||
optional: [INotebookShell],
|
||||
provides: IDocumentWidgetOpener,
|
||||
activate: (app: JupyterFrontEnd) => {
|
||||
activate: (app: JupyterFrontEnd, notebookShell: INotebookShell | null) => {
|
||||
const baseUrl = PageConfig.getBaseUrl();
|
||||
const docRegistry = app.docRegistry;
|
||||
let id = 0;
|
||||
return new (class {
|
||||
open(widget: IDocumentWidget, options?: DocumentRegistry.IOpenOptions) {
|
||||
const widgetName = options?.type;
|
||||
const widgetName = options?.type ?? '';
|
||||
const ref = options?.ref;
|
||||
// check if there is an setting override and if it would add the widget in the main area
|
||||
const userLayoutArea = notebookShell?.userLayout?.[widgetName]?.area;
|
||||
|
||||
if (ref !== '_noref') {
|
||||
if (ref !== '_noref' && userLayoutArea === undefined) {
|
||||
const path = widget.context.path;
|
||||
const ext = PathExt.extname(path);
|
||||
let route = 'edit';
|
||||
|
@ -359,7 +359,7 @@ const notebookToolsWidget: JupyterFrontEndPlugin<void> = {
|
||||
|
||||
// Add the notebook tools in right area.
|
||||
if (notebookTools) {
|
||||
shell.add(notebookTools, 'right');
|
||||
shell.add(notebookTools, 'right', { type: 'Property Inspector' });
|
||||
}
|
||||
};
|
||||
shell.currentChanged.connect(onChange);
|
||||
@ -388,7 +388,9 @@ const trusted: JupyterFrontEndPlugin<void> = {
|
||||
await current.context.ready;
|
||||
|
||||
const widget = TrustedComponent.create({ notebook, translator });
|
||||
notebookShell.add(widget, 'menu', { rank: 11_000 });
|
||||
notebookShell.add(widget, 'menu', {
|
||||
rank: 11_000,
|
||||
});
|
||||
};
|
||||
|
||||
notebookShell.currentChanged.connect(onChange);
|
||||
|
44
ui-tests/test/layout.spec.ts
Normal file
44
ui-tests/test/layout.spec.ts
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright (c) Jupyter Development Team.
|
||||
// Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import path from 'path';
|
||||
|
||||
import { expect } from '@playwright/test';
|
||||
|
||||
import { galata } from '@jupyterlab/galata';
|
||||
|
||||
import { test } from './fixtures';
|
||||
|
||||
test.use({
|
||||
mockSettings: {
|
||||
...galata.DEFAULT_SETTINGS,
|
||||
'@jupyter-notebook/application-extension:shell': {
|
||||
layout: {
|
||||
Debugger: { area: 'left' },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
test.describe('Layout Customization', () => {
|
||||
test('The Debugger panel should respect the settings and open in the left area', async ({
|
||||
page,
|
||||
tmpPath,
|
||||
}) => {
|
||||
const notebook = 'simple.ipynb';
|
||||
await page.contents.uploadFile(
|
||||
path.resolve(__dirname, `./notebooks/${notebook}`),
|
||||
`${tmpPath}/${notebook}`
|
||||
);
|
||||
await page.goto(`notebooks/${tmpPath}/${notebook}`);
|
||||
|
||||
const menuPath = 'View>Left Sidebar>Show Debugger';
|
||||
|
||||
await page.menu.clickMenuItem(menuPath);
|
||||
|
||||
const panel = page.locator('#jp-left-stack');
|
||||
expect(await panel.isVisible()).toBe(true);
|
||||
|
||||
expect(await panel.screenshot()).toMatchSnapshot('debugger.png');
|
||||
});
|
||||
});
|
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
Loading…
x
Reference in New Issue
Block a user