|
| 1 | +import { JupyterFrontEndPlugin } from '@jupyterlab/application'; |
1 | 2 | import { |
2 | | - ILabShell, |
3 | | - ILayoutRestorer, |
4 | | - IRouter, |
5 | | - JupyterFrontEnd, |
6 | | - JupyterFrontEndPlugin |
7 | | -} from '@jupyterlab/application'; |
8 | | -import { |
9 | | - IFileBrowserFactory, |
10 | | - FileBrowser, |
11 | | - Uploader |
12 | | -} from '@jupyterlab/filebrowser'; |
13 | | -import { ITranslator } from '@jupyterlab/translation'; |
14 | | -import { addJupyterLabThemeChangeListener } from '@jupyter/web-components'; |
15 | | -import { |
16 | | - createToolbarFactory, |
17 | | - IToolbarWidgetRegistry, |
18 | | - setToolbar, |
19 | | - Dialog, |
20 | | - showDialog |
21 | | -} from '@jupyterlab/apputils'; |
22 | | -import { ISettingRegistry } from '@jupyterlab/settingregistry'; |
23 | | -import { FilenameSearcher, IScore } from '@jupyterlab/ui-components'; |
24 | | -import { CommandRegistry } from '@lumino/commands'; |
25 | | - |
26 | | -import { DriveListModel, DriveListView, IDrive } from './drivelistmanager'; |
27 | | -import { DriveIcon, driveBrowserIcon } from './icons'; |
28 | | -import { Drive } from './contents'; |
29 | | -import { getDrivesList, setListingLimit } from './requests'; |
30 | | -import { IDriveInfo, IDrivesList } from './token'; |
31 | | -import { launcherPlugin } from './launcher'; |
32 | | - |
33 | | -/** |
34 | | - * The command IDs used by the driveBrowser plugin. |
35 | | - */ |
36 | | -namespace CommandIDs { |
37 | | - export const openDrivesDialog = 'drives:open-drives-dialog'; |
38 | | - export const openPath = 'drives:open-path'; |
39 | | - export const toggleBrowser = 'drives:toggle-main'; |
40 | | -} |
41 | | - |
42 | | -/** |
43 | | - * The file browser factory ID. |
44 | | - */ |
45 | | -const FILE_BROWSER_FACTORY = 'DriveBrowser'; |
46 | | - |
47 | | -/** |
48 | | - * The class name added to the drive filebrowser filterbox node. |
49 | | - */ |
50 | | -const FILTERBOX_CLASS = 'jp-drive-browser-search-box'; |
51 | | - |
52 | | -const openDriveDialogPlugin: JupyterFrontEndPlugin<void> = { |
53 | | - id: 'jupyter-drives:widget', |
54 | | - description: 'Open a dialog to select drives to be added in the filebrowser.', |
55 | | - requires: [IFileBrowserFactory, ITranslator], |
56 | | - autoStart: true, |
57 | | - activate: ( |
58 | | - app: JupyterFrontEnd, |
59 | | - factory: IFileBrowserFactory, |
60 | | - translator: ITranslator |
61 | | - ): void => { |
62 | | - addJupyterLabThemeChangeListener(); |
63 | | - const { commands } = app; |
64 | | - const { tracker } = factory; |
65 | | - const trans = translator.load('jupyter_drives'); |
66 | | - const selectedDrivesModelMap = new Map<IDrive[], DriveListModel>(); |
67 | | - |
68 | | - let selectedDrives: IDrive[] = [ |
69 | | - { |
70 | | - name: 'CoconutDrive', |
71 | | - url: '/coconut/url' |
72 | | - } |
73 | | - ]; |
74 | | - |
75 | | - const availableDrives: IDrive[] = [ |
76 | | - { |
77 | | - name: 'CoconutDrive', |
78 | | - url: '/coconut/url' |
79 | | - }, |
80 | | - { |
81 | | - name: 'PearDrive', |
82 | | - url: '/pear/url' |
83 | | - }, |
84 | | - { |
85 | | - name: 'StrawberryDrive', |
86 | | - url: '/strawberrydrive/url' |
87 | | - }, |
88 | | - { |
89 | | - name: 'BlueberryDrive', |
90 | | - url: '/blueberrydrive/url' |
91 | | - }, |
92 | | - { |
93 | | - name: '', |
94 | | - url: '/mydrive/url' |
95 | | - }, |
96 | | - { |
97 | | - name: 'RaspberryDrive', |
98 | | - url: '/raspberrydrive/url' |
99 | | - }, |
100 | | - |
101 | | - { |
102 | | - name: 'PineAppleDrive', |
103 | | - url: '' |
104 | | - }, |
105 | | - |
106 | | - { name: 'PomeloDrive', url: '/https://pomelodrive/url' }, |
107 | | - { |
108 | | - name: 'OrangeDrive', |
109 | | - url: '' |
110 | | - }, |
111 | | - { |
112 | | - name: 'TomatoDrive', |
113 | | - url: '' |
114 | | - }, |
115 | | - { |
116 | | - name: '', |
117 | | - url: 'superDrive/url' |
118 | | - }, |
119 | | - { |
120 | | - name: 'AvocadoDrive', |
121 | | - url: '' |
122 | | - } |
123 | | - ]; |
124 | | - let model = selectedDrivesModelMap.get(selectedDrives); |
125 | | - |
126 | | - //const model = new DriveListModel(availableDrives, selectedDrives); |
127 | | - |
128 | | - commands.addCommand(CommandIDs.openDrivesDialog, { |
129 | | - execute: args => { |
130 | | - const widget = tracker.currentWidget; |
131 | | - |
132 | | - if (!model) { |
133 | | - model = new DriveListModel(availableDrives, selectedDrives); |
134 | | - selectedDrivesModelMap.set(selectedDrives, model); |
135 | | - } else { |
136 | | - selectedDrives = model.selectedDrives; |
137 | | - selectedDrivesModelMap.set(selectedDrives, model); |
138 | | - } |
139 | | - if (widget) { |
140 | | - if (model) { |
141 | | - showDialog({ |
142 | | - body: new DriveListView(model), |
143 | | - buttons: [Dialog.cancelButton()] |
144 | | - }); |
145 | | - } |
146 | | - } |
147 | | - }, |
148 | | - |
149 | | - icon: DriveIcon.bindprops({ stylesheet: 'menuItem' }), |
150 | | - caption: trans.__('Add drives to filebrowser.'), |
151 | | - label: trans.__('Add Drives To Filebrowser') |
152 | | - }); |
153 | | - } |
154 | | -}; |
155 | | - |
156 | | -/** |
157 | | - * The drives list provider. |
158 | | - */ |
159 | | -const drivesListProvider: JupyterFrontEndPlugin<IDriveInfo[]> = { |
160 | | - id: 'jupyter-drives:drives-list', |
161 | | - description: 'The drives list provider.', |
162 | | - provides: IDrivesList, |
163 | | - activate: async (_: JupyterFrontEnd): Promise<IDriveInfo[]> => { |
164 | | - let drives: IDriveInfo[] = []; |
165 | | - try { |
166 | | - drives = await getDrivesList(); |
167 | | - } catch (error) { |
168 | | - console.log('Failed loading available drives list, with error: ', error); |
169 | | - } |
170 | | - return drives; |
171 | | - } |
172 | | -}; |
173 | | - |
174 | | -/** |
175 | | - * The drive file browser factory provider. |
176 | | - */ |
177 | | -const driveFileBrowser: JupyterFrontEndPlugin<void> = { |
178 | | - id: 'jupyter-drives:drives-file-browser', |
179 | | - description: 'The drive file browser factory provider.', |
180 | | - autoStart: true, |
181 | | - requires: [ |
182 | | - IFileBrowserFactory, |
183 | | - IToolbarWidgetRegistry, |
184 | | - ISettingRegistry, |
185 | | - ITranslator, |
186 | | - IDrivesList |
187 | | - ], |
188 | | - optional: [ |
189 | | - IRouter, |
190 | | - JupyterFrontEnd.ITreeResolver, |
191 | | - ILabShell, |
192 | | - ILayoutRestorer |
193 | | - ], |
194 | | - activate: async ( |
195 | | - app: JupyterFrontEnd, |
196 | | - fileBrowserFactory: IFileBrowserFactory, |
197 | | - toolbarRegistry: IToolbarWidgetRegistry, |
198 | | - settingsRegistry: ISettingRegistry, |
199 | | - translator: ITranslator, |
200 | | - drivesList: IDriveInfo[], |
201 | | - router: IRouter | null, |
202 | | - tree: JupyterFrontEnd.ITreeResolver | null, |
203 | | - labShell: ILabShell | null, |
204 | | - restorer: ILayoutRestorer | null |
205 | | - ): Promise<void> => { |
206 | | - console.log( |
207 | | - 'JupyterLab extension jupyter-drives:drives-file-browser is activated!' |
208 | | - ); |
209 | | - const { commands } = app; |
210 | | - |
211 | | - // create drive for drive file browser |
212 | | - const drive = new Drive({ |
213 | | - name: 's3', |
214 | | - drivesList: drivesList |
215 | | - }); |
216 | | - |
217 | | - app.serviceManager.contents.addDrive(drive); |
218 | | - |
219 | | - // get registered file types |
220 | | - drive.getRegisteredFileTypes(app); |
221 | | - |
222 | | - // Manually restore and load the drive file browser. |
223 | | - const driveBrowser = fileBrowserFactory.createFileBrowser('drivebrowser', { |
224 | | - auto: false, |
225 | | - restore: false, |
226 | | - driveName: drive.name |
227 | | - }); |
228 | | - |
229 | | - // Set attributes when adding the browser to the UI |
230 | | - driveBrowser.node.setAttribute('role', 'region'); |
231 | | - driveBrowser.node.setAttribute('aria-label', 'Drive Browser Section'); |
232 | | - driveBrowser.title.icon = driveBrowserIcon; |
233 | | - driveBrowser.title.caption = 'Drive File Browser'; |
234 | | - driveBrowser.id = 'drive-file-browser'; |
235 | | - |
236 | | - void Private.restoreBrowser(driveBrowser, commands, router, tree, labShell); |
237 | | - |
238 | | - app.shell.add(driveBrowser, 'left', { rank: 102, type: 'File Browser' }); |
239 | | - if (restorer) { |
240 | | - restorer.add(driveBrowser, 'drive-file-browser'); |
241 | | - } |
242 | | - |
243 | | - toolbarRegistry.addFactory( |
244 | | - FILE_BROWSER_FACTORY, |
245 | | - 'uploader', |
246 | | - (fileBrowser: FileBrowser) => |
247 | | - new Uploader({ model: fileBrowser.model, translator }) |
248 | | - ); |
249 | | - |
250 | | - toolbarRegistry.addFactory( |
251 | | - FILE_BROWSER_FACTORY, |
252 | | - 'file-name-searcher', |
253 | | - (fileBrowser: FileBrowser) => { |
254 | | - const searcher = FilenameSearcher({ |
255 | | - updateFilter: ( |
256 | | - filterFn: (item: string) => Partial<IScore> | null, |
257 | | - query?: string |
258 | | - ) => { |
259 | | - fileBrowser.model.setFilter(value => { |
260 | | - return filterFn(value.name.toLowerCase()); |
261 | | - }); |
262 | | - }, |
263 | | - useFuzzyFilter: true, |
264 | | - placeholder: 'Filter files by names', |
265 | | - forceRefresh: true |
266 | | - }); |
267 | | - searcher.addClass(FILTERBOX_CLASS); |
268 | | - return searcher; |
269 | | - } |
270 | | - ); |
271 | | - |
272 | | - // connect the filebrowser toolbar to the settings registry for the plugin |
273 | | - setToolbar( |
274 | | - driveBrowser, |
275 | | - createToolbarFactory( |
276 | | - toolbarRegistry, |
277 | | - settingsRegistry, |
278 | | - FILE_BROWSER_FACTORY, |
279 | | - driveFileBrowser.id, |
280 | | - translator |
281 | | - ) |
282 | | - ); |
283 | | - |
284 | | - /** |
285 | | - * Load the settings for this extension |
286 | | - * |
287 | | - * @param setting Extension settings |
288 | | - */ |
289 | | - function loadSetting(setting: ISettingRegistry.ISettings): void { |
290 | | - // Read the settings and convert to the correct type |
291 | | - const maxFilesListed = setting.get('maxFilesListed').composite as number; |
292 | | - // Set new limit. |
293 | | - setListingLimit(maxFilesListed); |
294 | | - } |
295 | | - |
296 | | - // Wait for the application to be restored and |
297 | | - // for the settings for this plugin to be loaded |
298 | | - Promise.all([app.restored, settingsRegistry.load(driveFileBrowser.id)]) |
299 | | - .then(([, setting]) => { |
300 | | - // Read the settings |
301 | | - loadSetting(setting); |
302 | | - |
303 | | - // Listen for your plugin setting changes using Signal |
304 | | - setting.changed.connect(loadSetting); |
305 | | - }) |
306 | | - .catch(reason => { |
307 | | - console.error( |
308 | | - `Something went wrong when reading the settings.\n${reason}` |
309 | | - ); |
310 | | - }); |
311 | | - } |
312 | | -}; |
| 3 | + driveFileBrowser, |
| 4 | + drivesListProvider, |
| 5 | + openDriveDialogPlugin, |
| 6 | + launcherPlugin |
| 7 | +} from './plugins'; |
313 | 8 |
|
314 | 9 | const plugins: JupyterFrontEndPlugin<any>[] = [ |
315 | 10 | driveFileBrowser, |
316 | 11 | drivesListProvider, |
317 | 12 | openDriveDialogPlugin, |
318 | 13 | launcherPlugin |
319 | 14 | ]; |
320 | | -export default plugins; |
321 | | - |
322 | | -namespace Private { |
323 | | - /** |
324 | | - * Restores file browser state and overrides state if tree resolver resolves. |
325 | | - */ |
326 | | - export async function restoreBrowser( |
327 | | - browser: FileBrowser, |
328 | | - commands: CommandRegistry, |
329 | | - router: IRouter | null, |
330 | | - tree: JupyterFrontEnd.ITreeResolver | null, |
331 | | - labShell: ILabShell | null |
332 | | - ): Promise<void> { |
333 | | - const restoring = 'jp-mod-restoring'; |
334 | 15 |
|
335 | | - browser.addClass(restoring); |
336 | | - |
337 | | - if (!router) { |
338 | | - await browser.model.restore(browser.id); |
339 | | - await browser.model.refresh(); |
340 | | - browser.removeClass(restoring); |
341 | | - return; |
342 | | - } |
343 | | - |
344 | | - const listener = async () => { |
345 | | - router.routed.disconnect(listener); |
346 | | - |
347 | | - const paths = await tree?.paths; |
348 | | - if (paths?.file || paths?.browser) { |
349 | | - // Restore the model without populating it. |
350 | | - await browser.model.restore(browser.id, false); |
351 | | - if (paths.file) { |
352 | | - await commands.execute(CommandIDs.openPath, { |
353 | | - path: paths.file, |
354 | | - dontShowBrowser: true |
355 | | - }); |
356 | | - } |
357 | | - if (paths.browser) { |
358 | | - await commands.execute(CommandIDs.openPath, { |
359 | | - path: paths.browser, |
360 | | - dontShowBrowser: true |
361 | | - }); |
362 | | - } |
363 | | - } else { |
364 | | - await browser.model.restore(browser.id); |
365 | | - await browser.model.refresh(); |
366 | | - } |
367 | | - browser.removeClass(restoring); |
368 | | - |
369 | | - if (labShell?.isEmpty('main')) { |
370 | | - void commands.execute('launcher:create'); |
371 | | - } |
372 | | - }; |
373 | | - router.routed.connect(listener); |
374 | | - } |
375 | | -} |
| 16 | +export default plugins; |
0 commit comments