Skip to content
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

Add nebar:open-proxy command for menu customization #1

Merged
merged 6 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ jobs:
- name: Install the extension
run: |
set -eux
python -m pip install "jupyterlab>=4.0.0,<5" jupyterlab_nebari_mode*.whl
WHEEL=$(ls jupyterlab_nebari_mode*.whl)
python -m pip install "jupyterlab>=4.0.0,<5" "$WHEEL[integration-test]"

- name: Install dependencies
working-directory: ui-tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update-integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
run: |
set -eux
jlpm
python -m pip install .
python -m pip install .[integration-test]

- uses: jupyterlab/maintainer-tools/.github/actions/update-snapshots@v1
with:
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ Nebari customizations for JupyterLab.

- `jupyterlab-nebari-mode:logo`: replaces `@jupyterlab/application-extension:logo`, adding clickable Nebari logo:
![](https://raw.githubusercontent.com/nebari-dev/jupyterlab-nebari-mode/main/ui-tests/tests/jupyterlab_nebari_mode.spec.ts-snapshots/top-panel-linux.png)
- `jupyterlab-nebari-mode:commands` adds `nebari:open-proxy` command for opening proxied processes, such as VSCode. This command can be used to add a menu entry, e.g.:
```json
{
"command": "nebari:open-proxy",
"rank": 1,
"args": {
"name": "vscode"
}
}
```

## Requirements

Expand Down
5 changes: 3 additions & 2 deletions binder/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ dependencies:
- nodejs >=18,<19
- pip
- wheel
# additional packages for demos
# - ipywidgets
- pip:
- jupyter-server-proxy
- jupyter-vscode-proxy
21 changes: 21 additions & 0 deletions binder/overrides.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"@jupyterlab/mainmenu-extension:plugin": {
"menus": [
{
"id": "jp-mainmenu-services",
"disabled": false,
"label": "Services",
"rank": 1000,
"items": [
{
"command": "nebari:open-proxy",
"rank": 1,
"args": {
"name": "vscode"
}
}
]
}
]
}
}
5 changes: 5 additions & 0 deletions binder/postBuild
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

python3 binder/postBuild
"""
import os
import subprocess
import sys
from pathlib import Path
Expand Down Expand Up @@ -42,6 +43,10 @@ _("jupyter", "server", "extension", "list")
# initially list installed extensions to determine if there are any surprises
_("jupyter", "labextension", "list")

# copy overrides.json to right location
NB_PYTHON_PREFIX = os.environ["NB_PYTHON_PREFIX"]
_("mkdir", "-p", f"{NB_PYTHON_PREFIX}/share/jupyter/lab/settings/")
_("cp", "binder/overrides.json", f"{NB_PYTHON_PREFIX}/share/jupyter/lab/settings/")

print("JupyterLab with jupyterlab_nebari_mode is ready to run with:\n")
print("\tjupyter lab\n")
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jupyterlab-nebari-mode",
"version": "0.1.0",
"version": "0.2.0",
"description": "Nebari customizations for JupyterLab.",
"keywords": [
"jupyter",
Expand Down Expand Up @@ -59,6 +59,7 @@
"@jupyterlab/application": "^4.0.0"
},
"devDependencies": {
"@jupyterhub/jupyter-server-proxy": "^4.1.0",
"@jupyterlab/builder": "^4.0.0",
"@jupyterlab/testutils": "^4.0.0",
"@types/jest": "^29.2.0",
Expand Down
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ dependencies = [
]
dynamic = ["version", "description", "authors", "urls", "keywords"]

[project.optional-dependencies]
integration-test = [
"jupyter-server-proxy",
"jupyter-vscode-proxy"
]

[tool.hatch.version]
source = "nodejs"

Expand Down
87 changes: 82 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { IServersInfo } from '@jupyterhub/jupyter-server-proxy/lib/tokens';
import {
ILabShell,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '@jupyterlab/application';
import { URLExt } from '@jupyterlab/coreutils';
import { ServerConnection } from '@jupyterlab/services';
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
import { Widget } from '@lumino/widgets';
import { nebariIcon } from './icons';

Expand Down Expand Up @@ -47,9 +49,82 @@ class NebariLogo extends Widget {
}
}

/**
* Initialization data for the jupyterlab-nebari-mode extension.
*/
namespace CommandIDs {
/**
* Opens a process proxied by jupyter-server-proxy (such as VSCode).
*/
export const openProxy = 'nebari:open-proxy';
}

interface IOpenProxyArgs {
/**
* Name of the server process to open.
*/
name?: string;
}

const commandsPlugin: JupyterFrontEndPlugin<void> = {
id: 'jupyterlab-nebari-mode:commands',
description: 'Adds additional commands used by nebari.',
autoStart: true,
requires: [],
activate: async (app: JupyterFrontEnd) => {
const serverSettings = ServerConnection.makeSettings();
const baseUrl = PageConfig.getBaseUrl();
const url = URLExt.join(baseUrl, 'server-proxy/servers-info');
const response = await ServerConnection.makeRequest(
url,
{},
serverSettings
);
if (!response.ok) {
console.warn('Server proxy info not available');
return;
}
const data = (await response.json()) as IServersInfo;

const findProcess = (name?: string) => {
if (!name) {
return null;
}
const matches = data.server_processes.filter(
process => process.name === name
);
if (matches.length === 0) {
return null;
}
return matches[0];
};

app.commands.addCommand(CommandIDs.openProxy, {
execute: (args: IOpenProxyArgs) => {
const processs = findProcess(args.name);
if (!processs) {
throw Error(`Process for ${args.name} not found`);
}

const url = `${baseUrl}${processs.launcher_entry.path_info}`;

if (processs.new_browser_tab) {
window.open(url, '_blank', 'noopener,noreferrer');
} else {
window.location.href = url;
}
},
isEnabled: (args: IOpenProxyArgs) => {
const processs = findProcess(args.name);
return !!processs;
},
label: (args: IOpenProxyArgs) => {
const processs = findProcess(args.name);
return processs
? `Open ${processs.launcher_entry.title}`
: 'Open Proxied Process';
}
});
}
};

const logoPlugin: JupyterFrontEndPlugin<void> = {
id: 'jupyterlab-nebari-mode:logo',
description: 'Sets the application logo.',
Expand All @@ -65,4 +140,6 @@ const logoPlugin: JupyterFrontEndPlugin<void> = {
}
};

export default logoPlugin;
const plugins = [commandsPlugin, logoPlugin];

export default plugins;
20 changes: 20 additions & 0 deletions ui-tests/tests/jupyterlab_nebari_mode.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,23 @@ test('should swap Jupyter logo with clickable Nebari logo', async ({
await link.focus();
expect(await link.screenshot()).toMatchSnapshot('nebari-logo-focus.png');
});

test('should register custom commands', async ({ page }) => {
const openVScodeProxy = await page.evaluate(async () => {
const registry = window.jupyterapp.commands;
const id = 'nebari:open-proxy';
const args = { name: 'vscode' };

return {
id,
label: registry.label(id, args),
isEnabled: registry.isEnabled(id, args)
};
});

// Should set correct label for given command
expect(openVScodeProxy.label).toBe('Open VS Code');

// Should be enabled when `jupyter-vscode-proxy` is installed
expect(openVScodeProxy.isEnabled).toBe(true);
});
34 changes: 32 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2092,7 +2092,18 @@ __metadata:
languageName: node
linkType: hard

"@jupyterlab/application@npm:^4.0.0, @jupyterlab/application@npm:^4.1.2":
"@jupyterhub/jupyter-server-proxy@npm:^4.1.0":
version: 4.1.0
resolution: "@jupyterhub/jupyter-server-proxy@npm:4.1.0"
dependencies:
"@jupyterlab/application": ^3.0 || ^4.0
"@jupyterlab/filebrowser": ^3.0 || ^4.0
"@jupyterlab/launcher": ^3.0 || ^4.0
checksum: d8006409ff0ca6029f00c7255447e052957bb4fa03ca02a1441ef277b128dde4f3d095c1f3ef920bb8e27c91386812bf81c3894b9cdac61b7dd9b70a616586df
languageName: node
linkType: hard

"@jupyterlab/application@npm:^3.0 || ^4.0, @jupyterlab/application@npm:^4.0.0, @jupyterlab/application@npm:^4.1.2":
version: 4.1.2
resolution: "@jupyterlab/application@npm:4.1.2"
dependencies:
Expand Down Expand Up @@ -2388,7 +2399,7 @@ __metadata:
languageName: node
linkType: hard

"@jupyterlab/filebrowser@npm:^4.1.2":
"@jupyterlab/filebrowser@npm:^3.0 || ^4.0, @jupyterlab/filebrowser@npm:^4.1.2":
version: 4.1.2
resolution: "@jupyterlab/filebrowser@npm:4.1.2"
dependencies:
Expand Down Expand Up @@ -2416,6 +2427,24 @@ __metadata:
languageName: node
linkType: hard

"@jupyterlab/launcher@npm:^3.0 || ^4.0":
version: 4.1.2
resolution: "@jupyterlab/launcher@npm:4.1.2"
dependencies:
"@jupyterlab/apputils": ^4.2.2
"@jupyterlab/translation": ^4.1.2
"@jupyterlab/ui-components": ^4.1.2
"@lumino/algorithm": ^2.0.1
"@lumino/commands": ^2.2.0
"@lumino/coreutils": ^2.1.2
"@lumino/disposable": ^2.1.2
"@lumino/properties": ^2.0.1
"@lumino/widgets": ^2.3.1
react: ^18.2.0
checksum: bc6f4fb53bf273e28b94b41ec9c87e7f2747053f3266519e1c2472dcc42636d10a80ecc99aaaa20d15ecd77230307dbba7696536177b01fb4631588ffa8bba53
languageName: node
linkType: hard

"@jupyterlab/lsp@npm:^4.1.2":
version: 4.1.2
resolution: "@jupyterlab/lsp@npm:4.1.2"
Expand Down Expand Up @@ -7199,6 +7228,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "jupyterlab-nebari-mode@workspace:."
dependencies:
"@jupyterhub/jupyter-server-proxy": ^4.1.0
"@jupyterlab/application": ^4.0.0
"@jupyterlab/builder": ^4.0.0
"@jupyterlab/testutils": ^4.0.0
Expand Down
Loading