Skip to content

Commit

Permalink
Improve integration with Notebook 7 (#16)
Browse files Browse the repository at this point in the history
* Handle opening a file from notebooks

* add missing deps

* handle edit

* fix apputils dep

* fix coreutils dep

* update binder

* fix handling of paths

* Add FIXME for Content-Disposition

* add config for memory storage

* lint
  • Loading branch information
jtpio authored Feb 15, 2024
1 parent f216f9d commit 7d144fe
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 15 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,7 @@ dmypy.json
# Yarn cache
.yarn/

# Generated
_temp_extension
_output
*.doit.db
7 changes: 4 additions & 3 deletions binder/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ channels:

dependencies:
# runtime dependencies
- python >=3.8,<3.9.0a0
- jupyterlab >=3,<4.0.0a0
- python >=3.11,<3.12
- jupyterlab >=4.0.10,<5
- notebook >=7.0.6,<8
# labextension build dependencies
- nodejs >=18,<19
- nodejs >=20,<21
- pip
- wheel
# additional packages for demos
Expand Down
8 changes: 8 additions & 0 deletions docs/jupyter-lite.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"jupyter-lite-schema-version": 0,
"jupyter-config-data": {
"enableMemoryStorage": true,
"settingsStorageDrivers": ["memoryStorageDriver"],
"contentsStorageDrivers": ["memoryStorageDriver"]
}
}
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@
"watch:src": "tsc -w --sourceMap"
},
"dependencies": {
"@jupyterlab/application": "^4.0.10"
"@jupyterlab/application": "^4.0.10",
"@jupyterlab/apputils": "^4.1.10",
"@jupyterlab/coreutils": "^6.0.10",
"@jupyterlab/filebrowser": "^4.0.10",
"@jupyterlab/translation": "^4.0.10"
},
"devDependencies": {
"@jupyterlab/builder": "^4.0.0",
Expand Down
88 changes: 77 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,39 @@ import {
JupyterFrontEndPlugin
} from '@jupyterlab/application';

import { PageConfig, URLExt } from '@jupyterlab/coreutils';
import { showErrorMessage } from '@jupyterlab/apputils';

import { PageConfig, PathExt, URLExt } from '@jupyterlab/coreutils';

import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';

import { ITranslator, nullTranslator } from '@jupyterlab/translation';

/**
* The regular expression matching the lab URL.
*/
const URL_PATTERN = new RegExp('/lab/?');
const URL_PATTERN = new RegExp('/(lab|notebooks|edit)/?');

/**
* Initialization data for the jupyterlab-open-url-parameter extension.
*/
const plugin: JupyterFrontEndPlugin<void> = {
id: 'jupyterlab-open-url-parameter:plugin',
autoStart: true,
requires: [IRouter],
activate: (app: JupyterFrontEnd, router: IRouter) => {
requires: [IRouter, ITranslator],
optional: [IDefaultFileBrowser],
activate: (
app: JupyterFrontEnd,
router: IRouter,
translator: ITranslator,
browser: IDefaultFileBrowser | null
) => {
const { commands } = app;
const trans = translator.load('jupyterlab') ?? nullTranslator;

const command = 'router:fromUrl';
commands.addCommand(command, {
execute: (args: any) => {
execute: async (args: any) => {
const parsed = args as IRouter.ILocation;
// use request to do the matching
const { request, search } = parsed;
Expand All @@ -35,20 +48,73 @@ const plugin: JupyterFrontEndPlugin<void> = {
const urlParams = new URLSearchParams(search);
const paramName = 'fromURL';
const paths = urlParams.getAll(paramName);
if (!paths) {
if (!paths || paths.length === 0) {
return;
}
const urls = paths.map(path => decodeURIComponent(path));
app.restored.then(() => {
// use the JupyterLab command to open the file from the URL
urls.forEach(url => {
void commands.execute('filebrowser:open-url', { url });
});

// handle the route and remove the fromURL parameter
const handleRoute = () => {
const url = new URL(URLExt.join(PageConfig.getBaseUrl(), request));
// only remove the fromURL parameter
url.searchParams.delete(paramName);
const { pathname, search } = url;
router.navigate(`${pathname}${search}`, { skipRouting: true });
};

// fetch the file from the URL and open it with the docmanager
const fetchAndOpen = async (url: string): Promise<void> => {
let type = '';
let blob;

// fetch the file from the URL
try {
const req = await fetch(url);
blob = await req.blob();
type = req.headers.get('Content-Type') ?? '';
} catch (err) {
const reason = err as any;
if (reason.response && reason.response.status !== 200) {
reason.message = trans.__('Could not open URL: %1', url);
}
return showErrorMessage(trans.__('Cannot fetch'), reason);
}

// upload the content of the file to the server
try {
// FIXME: handle Content-Disposition: https://github.com/jupyterlab/jupyterlab/issues/11531
const name = PathExt.basename(url);
const file = new File([blob], name, { type });
const model = await browser?.model.upload(file);
if (!model) {
return;
}
return commands.execute('docmanager:open', {
path: model.path,
options: {
ref: '_noref'
}
});
} catch (error) {
return showErrorMessage(
trans._p('showErrorMessage', 'Upload Error'),
error as Error
);
}
};

const [match] = matches;
// handle opening the URL with the Notebook 7 separately
if (match?.includes('/notebooks') || match?.includes('/edit')) {
const [first] = urls;
await fetchAndOpen(first);
handleRoute();
return;
}

app.restored.then(async () => {
await Promise.all(urls.map(url => fetchAndOpen(url)));
handleRoute();
});
}
});
Expand Down
55 changes: 55 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,29 @@ __metadata:
languageName: node
linkType: hard

"@jupyterlab/docmanager@npm:^4.0.10":
version: 4.0.10
resolution: "@jupyterlab/docmanager@npm:4.0.10"
dependencies:
"@jupyterlab/apputils": ^4.1.10
"@jupyterlab/coreutils": ^6.0.10
"@jupyterlab/docregistry": ^4.0.10
"@jupyterlab/services": ^7.0.10
"@jupyterlab/statusbar": ^4.0.10
"@jupyterlab/translation": ^4.0.10
"@jupyterlab/ui-components": ^4.0.10
"@lumino/algorithm": ^2.0.1
"@lumino/coreutils": ^2.1.2
"@lumino/disposable": ^2.1.2
"@lumino/messaging": ^2.0.1
"@lumino/properties": ^2.0.1
"@lumino/signaling": ^2.1.2
"@lumino/widgets": ^2.3.0
react: ^18.2.0
checksum: 8be669130f29f9245c75e6b03f2bf788da17e1026b1117e0bbd8fe84afca5a9fddfa27fa879231979db1a2bf62c3e9b50eb38586cc155a3e64e1c1dd2e528c9b
languageName: node
linkType: hard

"@jupyterlab/docregistry@npm:^4.0.10":
version: 4.0.10
resolution: "@jupyterlab/docregistry@npm:4.0.10"
Expand All @@ -426,6 +449,34 @@ __metadata:
languageName: node
linkType: hard

"@jupyterlab/filebrowser@npm:^4.0.10":
version: 4.0.10
resolution: "@jupyterlab/filebrowser@npm:4.0.10"
dependencies:
"@jupyterlab/apputils": ^4.1.10
"@jupyterlab/coreutils": ^6.0.10
"@jupyterlab/docmanager": ^4.0.10
"@jupyterlab/docregistry": ^4.0.10
"@jupyterlab/services": ^7.0.10
"@jupyterlab/statedb": ^4.0.10
"@jupyterlab/statusbar": ^4.0.10
"@jupyterlab/translation": ^4.0.10
"@jupyterlab/ui-components": ^4.0.10
"@lumino/algorithm": ^2.0.1
"@lumino/coreutils": ^2.1.2
"@lumino/disposable": ^2.1.2
"@lumino/domutils": ^2.0.1
"@lumino/dragdrop": ^2.1.4
"@lumino/messaging": ^2.0.1
"@lumino/polling": ^2.1.2
"@lumino/signaling": ^2.1.2
"@lumino/virtualdom": ^2.0.1
"@lumino/widgets": ^2.3.0
react: ^18.2.0
checksum: f19884d40b0b1761e023c939cae1f11112b3b021f75df4806d97d0434e8b25c651bb054a66f563faa99e46c4b2b820b54e6a0e48bffa49d0a0e7bce145c34852
languageName: node
linkType: hard

"@jupyterlab/nbformat@npm:^3.0.0 || ^4.0.0-alpha.21 || ^4.0.0, @jupyterlab/nbformat@npm:^4.0.10":
version: 4.0.10
resolution: "@jupyterlab/nbformat@npm:4.0.10"
Expand Down Expand Up @@ -3222,7 +3273,11 @@ __metadata:
resolution: "jupyterlab-open-url-parameter@workspace:."
dependencies:
"@jupyterlab/application": ^4.0.10
"@jupyterlab/apputils": ^4.1.10
"@jupyterlab/builder": ^4.0.0
"@jupyterlab/coreutils": ^6.0.10
"@jupyterlab/filebrowser": ^4.0.10
"@jupyterlab/translation": ^4.0.10
"@types/json-schema": ^7.0.11
"@types/react": ^18.0.26
"@types/react-addons-linked-state-mixin": ^0.14.22
Expand Down

0 comments on commit 7d144fe

Please sign in to comment.