@@ -4,26 +4,39 @@ import {
44 JupyterFrontEndPlugin
55} from '@jupyterlab/application' ;
66
7- import { PageConfig , URLExt } from '@jupyterlab/coreutils' ;
7+ import { showErrorMessage } from '@jupyterlab/apputils' ;
8+
9+ import { PageConfig , PathExt , URLExt } from '@jupyterlab/coreutils' ;
10+
11+ import { IDefaultFileBrowser } from '@jupyterlab/filebrowser' ;
12+
13+ import { ITranslator , nullTranslator } from '@jupyterlab/translation' ;
814
915/**
1016 * The regular expression matching the lab URL.
1117 */
12- const URL_PATTERN = new RegExp ( '/lab/?' ) ;
18+ const URL_PATTERN = new RegExp ( '/( lab|notebooks|edit) /?' ) ;
1319
1420/**
1521 * Initialization data for the jupyterlab-open-url-parameter extension.
1622 */
1723const plugin : JupyterFrontEndPlugin < void > = {
1824 id : 'jupyterlab-open-url-parameter:plugin' ,
1925 autoStart : true ,
20- requires : [ IRouter ] ,
21- activate : ( app : JupyterFrontEnd , router : IRouter ) => {
26+ requires : [ IRouter , ITranslator ] ,
27+ optional : [ IDefaultFileBrowser ] ,
28+ activate : (
29+ app : JupyterFrontEnd ,
30+ router : IRouter ,
31+ translator : ITranslator ,
32+ browser : IDefaultFileBrowser | null
33+ ) => {
2234 const { commands } = app ;
35+ const trans = translator . load ( 'jupyterlab' ) ?? nullTranslator ;
2336
2437 const command = 'router:fromUrl' ;
2538 commands . addCommand ( command , {
26- execute : ( args : any ) => {
39+ execute : async ( args : any ) => {
2740 const parsed = args as IRouter . ILocation ;
2841 // use request to do the matching
2942 const { request, search } = parsed ;
@@ -35,20 +48,73 @@ const plugin: JupyterFrontEndPlugin<void> = {
3548 const urlParams = new URLSearchParams ( search ) ;
3649 const paramName = 'fromURL' ;
3750 const paths = urlParams . getAll ( paramName ) ;
38- if ( ! paths ) {
51+ if ( ! paths || paths . length === 0 ) {
3952 return ;
4053 }
4154 const urls = paths . map ( path => decodeURIComponent ( path ) ) ;
42- app . restored . then ( ( ) => {
43- // use the JupyterLab command to open the file from the URL
44- urls . forEach ( url => {
45- void commands . execute ( 'filebrowser:open-url' , { url } ) ;
46- } ) ;
55+
56+ // handle the route and remove the fromURL parameter
57+ const handleRoute = ( ) => {
4758 const url = new URL ( URLExt . join ( PageConfig . getBaseUrl ( ) , request ) ) ;
4859 // only remove the fromURL parameter
4960 url . searchParams . delete ( paramName ) ;
5061 const { pathname, search } = url ;
5162 router . navigate ( `${ pathname } ${ search } ` , { skipRouting : true } ) ;
63+ } ;
64+
65+ // fetch the file from the URL and open it with the docmanager
66+ const fetchAndOpen = async ( url : string ) : Promise < void > => {
67+ let type = '' ;
68+ let blob ;
69+
70+ // fetch the file from the URL
71+ try {
72+ const req = await fetch ( url ) ;
73+ blob = await req . blob ( ) ;
74+ type = req . headers . get ( 'Content-Type' ) ?? '' ;
75+ } catch ( err ) {
76+ const reason = err as any ;
77+ if ( reason . response && reason . response . status !== 200 ) {
78+ reason . message = trans . __ ( 'Could not open URL: %1' , url ) ;
79+ }
80+ return showErrorMessage ( trans . __ ( 'Cannot fetch' ) , reason ) ;
81+ }
82+
83+ // upload the content of the file to the server
84+ try {
85+ // FIXME: handle Content-Disposition: https://github.com/jupyterlab/jupyterlab/issues/11531
86+ const name = PathExt . basename ( url ) ;
87+ const file = new File ( [ blob ] , name , { type } ) ;
88+ const model = await browser ?. model . upload ( file ) ;
89+ if ( ! model ) {
90+ return ;
91+ }
92+ return commands . execute ( 'docmanager:open' , {
93+ path : model . path ,
94+ options : {
95+ ref : '_noref'
96+ }
97+ } ) ;
98+ } catch ( error ) {
99+ return showErrorMessage (
100+ trans . _p ( 'showErrorMessage' , 'Upload Error' ) ,
101+ error as Error
102+ ) ;
103+ }
104+ } ;
105+
106+ const [ match ] = matches ;
107+ // handle opening the URL with the Notebook 7 separately
108+ if ( match ?. includes ( '/notebooks' ) || match ?. includes ( '/edit' ) ) {
109+ const [ first ] = urls ;
110+ await fetchAndOpen ( first ) ;
111+ handleRoute ( ) ;
112+ return ;
113+ }
114+
115+ app . restored . then ( async ( ) => {
116+ await Promise . all ( urls . map ( url => fetchAndOpen ( url ) ) ) ;
117+ handleRoute ( ) ;
52118 } ) ;
53119 }
54120 } ) ;
0 commit comments