@jupyterlab/filebrowser 4.1.0-alpha.2 → 4.1.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser.d.ts +5 -0
- package/lib/browser.js +9 -2
- package/lib/browser.js.map +1 -1
- package/lib/crumbs.d.ts +11 -0
- package/lib/crumbs.js +60 -18
- package/lib/crumbs.js.map +1 -1
- package/lib/listing.js +2 -0
- package/lib/listing.js.map +1 -1
- package/lib/opendialog.d.ts +4 -0
- package/lib/opendialog.js +56 -35
- package/lib/opendialog.js.map +1 -1
- package/package.json +15 -15
- package/src/browser.ts +11 -2
- package/src/crumbs.ts +79 -24
- package/src/listing.ts +2 -0
- package/src/opendialog.ts +81 -38
- package/style/base.css +4 -4
package/lib/opendialog.d.ts
CHANGED
package/lib/opendialog.js
CHANGED
|
@@ -7,6 +7,7 @@ import { newFolderIcon, refreshIcon } from '@jupyterlab/ui-components';
|
|
|
7
7
|
import { PanelLayout, Widget } from '@lumino/widgets';
|
|
8
8
|
import { FileBrowser } from './browser';
|
|
9
9
|
import { FilterFileBrowserModel } from './model';
|
|
10
|
+
import { PromiseDelegate } from '@lumino/coreutils';
|
|
10
11
|
/**
|
|
11
12
|
* The class name added to open file dialog
|
|
12
13
|
*/
|
|
@@ -26,9 +27,10 @@ export var FileDialog;
|
|
|
26
27
|
*
|
|
27
28
|
* @returns A promise that resolves with whether the dialog was accepted.
|
|
28
29
|
*/
|
|
29
|
-
function getOpenFiles(options) {
|
|
30
|
+
async function getOpenFiles(options) {
|
|
30
31
|
const translator = options.translator || nullTranslator;
|
|
31
32
|
const trans = translator.load('jupyterlab');
|
|
33
|
+
const openDialog = new OpenDialog(options.manager, options.filter, translator, options.defaultPath);
|
|
32
34
|
const dialogOptions = {
|
|
33
35
|
title: options.title,
|
|
34
36
|
buttons: [
|
|
@@ -40,8 +42,9 @@ export var FileDialog;
|
|
|
40
42
|
focusNodeSelector: options.focusNodeSelector,
|
|
41
43
|
host: options.host,
|
|
42
44
|
renderer: options.renderer,
|
|
43
|
-
body:
|
|
45
|
+
body: openDialog
|
|
44
46
|
};
|
|
47
|
+
await openDialog.ready;
|
|
45
48
|
const dialog = new Dialog(dialogOptions);
|
|
46
49
|
return dialog.launch();
|
|
47
50
|
}
|
|
@@ -70,42 +73,51 @@ export var FileDialog;
|
|
|
70
73
|
* Open dialog widget
|
|
71
74
|
*/
|
|
72
75
|
class OpenDialog extends Widget {
|
|
73
|
-
constructor(manager, filter, translator, filterDirectories) {
|
|
76
|
+
constructor(manager, filter, translator, defaultPath, filterDirectories) {
|
|
74
77
|
super();
|
|
78
|
+
this._ready = new PromiseDelegate();
|
|
75
79
|
translator = translator !== null && translator !== void 0 ? translator : nullTranslator;
|
|
76
80
|
const trans = translator.load('jupyterlab');
|
|
77
81
|
this.addClass(OPEN_DIALOG_CLASS);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
82
|
+
Private.createFilteredFileBrowser('filtered-file-browser-dialog', manager, filter, {}, translator, defaultPath, filterDirectories)
|
|
83
|
+
.then(browser => {
|
|
84
|
+
this._browser = browser;
|
|
85
|
+
// Add toolbar items
|
|
86
|
+
setToolbar(this._browser, (browser) => [
|
|
87
|
+
{
|
|
88
|
+
name: 'new-folder',
|
|
89
|
+
widget: new ToolbarButton({
|
|
90
|
+
icon: newFolderIcon,
|
|
91
|
+
onClick: () => {
|
|
92
|
+
void browser.createNewDirectory();
|
|
93
|
+
},
|
|
94
|
+
tooltip: trans.__('New Folder')
|
|
95
|
+
})
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: 'refresher',
|
|
99
|
+
widget: new ToolbarButton({
|
|
100
|
+
icon: refreshIcon,
|
|
101
|
+
onClick: () => {
|
|
102
|
+
browser.model.refresh().catch(reason => {
|
|
103
|
+
console.error('Failed to refresh file browser in open dialog.', reason);
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
tooltip: trans.__('Refresh File List')
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
]);
|
|
110
|
+
// Build the sub widgets
|
|
111
|
+
const layout = new PanelLayout();
|
|
112
|
+
layout.addWidget(this._browser);
|
|
113
|
+
// Set Widget content
|
|
114
|
+
this.layout = layout;
|
|
115
|
+
this._ready.resolve();
|
|
116
|
+
})
|
|
117
|
+
.catch(reason => {
|
|
118
|
+
console.error('Error while creating file browser in open dialog', reason);
|
|
119
|
+
this._ready.reject(void 0);
|
|
120
|
+
});
|
|
109
121
|
}
|
|
110
122
|
/**
|
|
111
123
|
* Get the selected items.
|
|
@@ -132,6 +144,12 @@ class OpenDialog extends Widget {
|
|
|
132
144
|
return selection;
|
|
133
145
|
}
|
|
134
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* A promise that resolves when openDialog is successfully created.
|
|
149
|
+
*/
|
|
150
|
+
get ready() {
|
|
151
|
+
return this._ready.promise;
|
|
152
|
+
}
|
|
135
153
|
}
|
|
136
154
|
var Private;
|
|
137
155
|
(function (Private) {
|
|
@@ -157,7 +175,7 @@ var Private;
|
|
|
157
175
|
* as the initial ID passed into the factory is used for only one file browser
|
|
158
176
|
* instance.
|
|
159
177
|
*/
|
|
160
|
-
Private.createFilteredFileBrowser = (id, manager, filter, options = {}, translator, filterDirectories) => {
|
|
178
|
+
Private.createFilteredFileBrowser = async (id, manager, filter, options = {}, translator, defaultPath, filterDirectories) => {
|
|
161
179
|
translator = translator || nullTranslator;
|
|
162
180
|
const model = new FilterFileBrowserModel({
|
|
163
181
|
manager,
|
|
@@ -167,6 +185,9 @@ var Private;
|
|
|
167
185
|
refreshInterval: options.refreshInterval,
|
|
168
186
|
filterDirectories
|
|
169
187
|
});
|
|
188
|
+
if (defaultPath) {
|
|
189
|
+
await model.cd(defaultPath);
|
|
190
|
+
}
|
|
170
191
|
const widget = new FileBrowser({
|
|
171
192
|
id,
|
|
172
193
|
model,
|
package/lib/opendialog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opendialog.js","sourceRoot":"","sources":["../src/opendialog.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,2DAA2D;AAE3D,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGhD,OAAO,EAAe,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAU,aAAa,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"opendialog.js","sourceRoot":"","sources":["../src/opendialog.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupyterlab/filebrowser",
|
|
3
|
-
"version": "4.1.0-alpha.
|
|
3
|
+
"version": "4.1.0-alpha.4",
|
|
4
4
|
"description": "JupyterLab - FileBrowser Widget",
|
|
5
5
|
"homepage": "https://github.com/jupyterlab/jupyterlab",
|
|
6
6
|
"bugs": {
|
|
@@ -42,34 +42,34 @@
|
|
|
42
42
|
"watch": "tsc -b --watch"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@jupyterlab/apputils": "^4.2.0-alpha.
|
|
46
|
-
"@jupyterlab/coreutils": "^6.1.0-alpha.
|
|
47
|
-
"@jupyterlab/docmanager": "^4.1.0-alpha.
|
|
48
|
-
"@jupyterlab/docregistry": "^4.1.0-alpha.
|
|
49
|
-
"@jupyterlab/services": "^7.1.0-alpha.
|
|
50
|
-
"@jupyterlab/statedb": "^4.1.0-alpha.
|
|
51
|
-
"@jupyterlab/statusbar": "^4.1.0-alpha.
|
|
52
|
-
"@jupyterlab/translation": "^4.1.0-alpha.
|
|
53
|
-
"@jupyterlab/ui-components": "^4.1.0-alpha.
|
|
45
|
+
"@jupyterlab/apputils": "^4.2.0-alpha.4",
|
|
46
|
+
"@jupyterlab/coreutils": "^6.1.0-alpha.4",
|
|
47
|
+
"@jupyterlab/docmanager": "^4.1.0-alpha.4",
|
|
48
|
+
"@jupyterlab/docregistry": "^4.1.0-alpha.4",
|
|
49
|
+
"@jupyterlab/services": "^7.1.0-alpha.4",
|
|
50
|
+
"@jupyterlab/statedb": "^4.1.0-alpha.4",
|
|
51
|
+
"@jupyterlab/statusbar": "^4.1.0-alpha.4",
|
|
52
|
+
"@jupyterlab/translation": "^4.1.0-alpha.4",
|
|
53
|
+
"@jupyterlab/ui-components": "^4.1.0-alpha.4",
|
|
54
54
|
"@lumino/algorithm": "^2.0.1",
|
|
55
55
|
"@lumino/coreutils": "^2.1.2",
|
|
56
56
|
"@lumino/disposable": "^2.1.2",
|
|
57
57
|
"@lumino/domutils": "^2.0.1",
|
|
58
|
-
"@lumino/dragdrop": "^2.1.
|
|
58
|
+
"@lumino/dragdrop": "^2.1.4",
|
|
59
59
|
"@lumino/messaging": "^2.0.1",
|
|
60
60
|
"@lumino/polling": "^2.1.2",
|
|
61
61
|
"@lumino/signaling": "^2.1.2",
|
|
62
62
|
"@lumino/virtualdom": "^2.0.1",
|
|
63
|
-
"@lumino/widgets": "^2.3.1
|
|
63
|
+
"@lumino/widgets": "^2.3.1",
|
|
64
64
|
"react": "^18.2.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@jupyterlab/testing": "^4.1.0-alpha.
|
|
67
|
+
"@jupyterlab/testing": "^4.1.0-alpha.4",
|
|
68
68
|
"@types/jest": "^29.2.0",
|
|
69
69
|
"jest": "^29.2.0",
|
|
70
|
-
"rimraf": "~
|
|
70
|
+
"rimraf": "~5.0.5",
|
|
71
71
|
"typedoc": "~0.24.7",
|
|
72
|
-
"typescript": "~5.
|
|
72
|
+
"typescript": "~5.1.6"
|
|
73
73
|
},
|
|
74
74
|
"publishConfig": {
|
|
75
75
|
"access": "public"
|
package/src/browser.ts
CHANGED
|
@@ -62,8 +62,6 @@ export class FileBrowser extends SidePanel {
|
|
|
62
62
|
model.connectionFailure.connect(this._onConnectionFailure, this);
|
|
63
63
|
this._manager = model.manager;
|
|
64
64
|
|
|
65
|
-
// a11y
|
|
66
|
-
this.toolbar.node.setAttribute('role', 'navigation');
|
|
67
65
|
this.toolbar.node.setAttribute(
|
|
68
66
|
'aria-label',
|
|
69
67
|
this._trans.__('file browser')
|
|
@@ -126,6 +124,17 @@ export class FileBrowser extends SidePanel {
|
|
|
126
124
|
}
|
|
127
125
|
}
|
|
128
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Whether to show the full path in the breadcrumbs
|
|
129
|
+
*/
|
|
130
|
+
get showFullPath(): boolean {
|
|
131
|
+
return this.crumbs.fullPath;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
set showFullPath(value: boolean) {
|
|
135
|
+
this.crumbs.fullPath = value;
|
|
136
|
+
}
|
|
137
|
+
|
|
129
138
|
/**
|
|
130
139
|
* Whether to show the file size column
|
|
131
140
|
*/
|
package/src/crumbs.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
folderIcon as rootIcon
|
|
16
16
|
} from '@jupyterlab/ui-components';
|
|
17
17
|
import { ArrayExt } from '@lumino/algorithm';
|
|
18
|
+
import { JSONExt } from '@lumino/coreutils';
|
|
18
19
|
import { ElementExt } from '@lumino/domutils';
|
|
19
20
|
import { Drag } from '@lumino/dragdrop';
|
|
20
21
|
import { Message } from '@lumino/messaging';
|
|
@@ -70,6 +71,7 @@ export class BreadCrumbs extends Widget {
|
|
|
70
71
|
this.translator = options.translator || nullTranslator;
|
|
71
72
|
this._trans = this.translator.load('jupyterlab');
|
|
72
73
|
this._model = options.model;
|
|
74
|
+
this._fullPath = options.fullPath || false;
|
|
73
75
|
this.addClass(BREADCRUMB_CLASS);
|
|
74
76
|
this._crumbs = Private.createCrumbs();
|
|
75
77
|
this._crumbSeps = Private.createCrumbSeparators();
|
|
@@ -114,6 +116,17 @@ export class BreadCrumbs extends Widget {
|
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Whether to show the full path in the breadcrumbs
|
|
121
|
+
*/
|
|
122
|
+
get fullPath(): boolean {
|
|
123
|
+
return this._fullPath;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
set fullPath(value: boolean) {
|
|
127
|
+
this._fullPath = value;
|
|
128
|
+
}
|
|
129
|
+
|
|
117
130
|
/**
|
|
118
131
|
* A message handler invoked on an `'after-attach'` message.
|
|
119
132
|
*/
|
|
@@ -148,12 +161,16 @@ export class BreadCrumbs extends Widget {
|
|
|
148
161
|
// Update the breadcrumb list.
|
|
149
162
|
const contents = this._model.manager.services.contents;
|
|
150
163
|
const localPath = contents.localPath(this._model.path);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
this.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
)
|
|
164
|
+
const state = {
|
|
165
|
+
path: localPath,
|
|
166
|
+
hasPreferred: this._hasPreferred,
|
|
167
|
+
fullPath: this._fullPath
|
|
168
|
+
};
|
|
169
|
+
if (this._previousState && JSONExt.deepEqual(state, this._previousState)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
this._previousState = state;
|
|
173
|
+
Private.updateCrumbs(this._crumbs, this._crumbSeps, state);
|
|
157
174
|
}
|
|
158
175
|
|
|
159
176
|
/**
|
|
@@ -184,12 +201,20 @@ export class BreadCrumbs extends Widget {
|
|
|
184
201
|
node.classList.contains(BREADCRUMB_ITEM_CLASS) ||
|
|
185
202
|
node.classList.contains(BREADCRUMB_ROOT_CLASS)
|
|
186
203
|
) {
|
|
187
|
-
|
|
204
|
+
let index = ArrayExt.findFirstIndex(
|
|
188
205
|
this._crumbs,
|
|
189
206
|
value => value === node
|
|
190
207
|
);
|
|
208
|
+
let destination = BREAD_CRUMB_PATHS[index];
|
|
209
|
+
if (
|
|
210
|
+
this._fullPath &&
|
|
211
|
+
index < 0 &&
|
|
212
|
+
!node.classList.contains(BREADCRUMB_ROOT_CLASS)
|
|
213
|
+
) {
|
|
214
|
+
destination = node.title;
|
|
215
|
+
}
|
|
191
216
|
this._model
|
|
192
|
-
.cd(
|
|
217
|
+
.cd(destination)
|
|
193
218
|
.catch(error =>
|
|
194
219
|
showErrorMessage(this._trans.__('Open Error'), error)
|
|
195
220
|
);
|
|
@@ -309,6 +334,8 @@ export class BreadCrumbs extends Widget {
|
|
|
309
334
|
private _hasPreferred: boolean;
|
|
310
335
|
private _crumbs: ReadonlyArray<HTMLElement>;
|
|
311
336
|
private _crumbSeps: ReadonlyArray<HTMLElement>;
|
|
337
|
+
private _fullPath: boolean;
|
|
338
|
+
private _previousState: Private.ICrumbsState | null = null;
|
|
312
339
|
}
|
|
313
340
|
|
|
314
341
|
/**
|
|
@@ -328,6 +355,11 @@ export namespace BreadCrumbs {
|
|
|
328
355
|
* The application language translator.
|
|
329
356
|
*/
|
|
330
357
|
translator?: ITranslator;
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Show the full file browser path in breadcrumbs
|
|
361
|
+
*/
|
|
362
|
+
fullPath?: boolean;
|
|
331
363
|
}
|
|
332
364
|
}
|
|
333
365
|
|
|
@@ -346,14 +378,23 @@ namespace Private {
|
|
|
346
378
|
Preferred
|
|
347
379
|
}
|
|
348
380
|
|
|
381
|
+
/**
|
|
382
|
+
* Breadcrumbs state.
|
|
383
|
+
*/
|
|
384
|
+
export interface ICrumbsState {
|
|
385
|
+
[key: string]: string | boolean;
|
|
386
|
+
path: string;
|
|
387
|
+
hasPreferred: boolean;
|
|
388
|
+
fullPath: boolean;
|
|
389
|
+
}
|
|
390
|
+
|
|
349
391
|
/**
|
|
350
392
|
* Populate the breadcrumb node.
|
|
351
393
|
*/
|
|
352
394
|
export function updateCrumbs(
|
|
353
395
|
breadcrumbs: ReadonlyArray<HTMLElement>,
|
|
354
396
|
separators: ReadonlyArray<HTMLElement>,
|
|
355
|
-
|
|
356
|
-
hasPreferred: boolean
|
|
397
|
+
state: ICrumbsState
|
|
357
398
|
): void {
|
|
358
399
|
const node = breadcrumbs[0].parentNode as HTMLElement;
|
|
359
400
|
|
|
@@ -363,33 +404,47 @@ namespace Private {
|
|
|
363
404
|
node.removeChild(firstChild.nextSibling);
|
|
364
405
|
}
|
|
365
406
|
|
|
366
|
-
if (hasPreferred) {
|
|
407
|
+
if (state.hasPreferred) {
|
|
367
408
|
node.appendChild(breadcrumbs[Crumb.Home]);
|
|
368
409
|
node.appendChild(separators[0]);
|
|
369
410
|
} else {
|
|
370
411
|
node.appendChild(separators[0]);
|
|
371
412
|
}
|
|
372
413
|
|
|
373
|
-
const parts = path.split('/');
|
|
374
|
-
if (parts.length > 2) {
|
|
414
|
+
const parts = state.path.split('/');
|
|
415
|
+
if (!state.fullPath && parts.length > 2) {
|
|
375
416
|
node.appendChild(breadcrumbs[Crumb.Ellipsis]);
|
|
376
417
|
const grandParent = parts.slice(0, parts.length - 2).join('/');
|
|
377
418
|
breadcrumbs[Crumb.Ellipsis].title = grandParent;
|
|
378
419
|
node.appendChild(separators[1]);
|
|
379
420
|
}
|
|
380
421
|
|
|
381
|
-
if (path) {
|
|
382
|
-
if (
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
422
|
+
if (state.path) {
|
|
423
|
+
if (!state.fullPath) {
|
|
424
|
+
if (parts.length >= 2) {
|
|
425
|
+
breadcrumbs[Crumb.Parent].textContent = parts[parts.length - 2];
|
|
426
|
+
node.appendChild(breadcrumbs[Crumb.Parent]);
|
|
427
|
+
const parent = parts.slice(0, parts.length - 1).join('/');
|
|
428
|
+
breadcrumbs[Crumb.Parent].title = parent;
|
|
429
|
+
node.appendChild(separators[2]);
|
|
430
|
+
}
|
|
431
|
+
breadcrumbs[Crumb.Current].textContent = parts[parts.length - 1];
|
|
432
|
+
node.appendChild(breadcrumbs[Crumb.Current]);
|
|
433
|
+
breadcrumbs[Crumb.Current].title = state.path;
|
|
434
|
+
node.appendChild(separators[3]);
|
|
435
|
+
} else {
|
|
436
|
+
for (let i = 0; i < parts.length; i++) {
|
|
437
|
+
const elem = document.createElement('span');
|
|
438
|
+
elem.className = BREADCRUMB_ITEM_CLASS;
|
|
439
|
+
elem.textContent = parts[i];
|
|
440
|
+
const elemPath = `/${parts.slice(0, i + 1).join('/')}`;
|
|
441
|
+
elem.title = elemPath;
|
|
442
|
+
node.appendChild(elem);
|
|
443
|
+
const separator = document.createElement('span');
|
|
444
|
+
separator.textContent = '/';
|
|
445
|
+
node.appendChild(separator);
|
|
446
|
+
}
|
|
388
447
|
}
|
|
389
|
-
breadcrumbs[Crumb.Current].textContent = parts[parts.length - 1];
|
|
390
|
-
node.appendChild(breadcrumbs[Crumb.Current]);
|
|
391
|
-
breadcrumbs[Crumb.Current].title = path;
|
|
392
|
-
node.appendChild(separators[3]);
|
|
393
448
|
}
|
|
394
449
|
}
|
|
395
450
|
|
package/src/listing.ts
CHANGED
|
@@ -2251,6 +2251,8 @@ export namespace DirListing {
|
|
|
2251
2251
|
const node = document.createElement('div');
|
|
2252
2252
|
const header = document.createElement('div');
|
|
2253
2253
|
const content = document.createElement('ul');
|
|
2254
|
+
// Allow the node to scroll while dragging items.
|
|
2255
|
+
content.setAttribute('data-lm-dragscroll', 'true');
|
|
2254
2256
|
content.className = CONTENT_CLASS;
|
|
2255
2257
|
header.className = HEADER_CLASS;
|
|
2256
2258
|
node.appendChild(header);
|
package/src/opendialog.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { PanelLayout, Widget } from '@lumino/widgets';
|
|
|
11
11
|
import { FileBrowser } from './browser';
|
|
12
12
|
import { FilterFileBrowserModel } from './model';
|
|
13
13
|
import { IFileBrowserFactory } from './tokens';
|
|
14
|
+
import { PromiseDelegate } from '@lumino/coreutils';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* The class name added to open file dialog
|
|
@@ -43,6 +44,11 @@ export namespace FileDialog {
|
|
|
43
44
|
* The application language translator.
|
|
44
45
|
*/
|
|
45
46
|
translator?: ITranslator;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Default path to open
|
|
50
|
+
*/
|
|
51
|
+
defaultPath?: string;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
/**
|
|
@@ -70,11 +76,17 @@ export namespace FileDialog {
|
|
|
70
76
|
*
|
|
71
77
|
* @returns A promise that resolves with whether the dialog was accepted.
|
|
72
78
|
*/
|
|
73
|
-
export function getOpenFiles(
|
|
79
|
+
export async function getOpenFiles(
|
|
74
80
|
options: IFileOptions
|
|
75
81
|
): Promise<Dialog.IResult<Contents.IModel[]>> {
|
|
76
82
|
const translator = options.translator || nullTranslator;
|
|
77
83
|
const trans = translator.load('jupyterlab');
|
|
84
|
+
const openDialog = new OpenDialog(
|
|
85
|
+
options.manager,
|
|
86
|
+
options.filter,
|
|
87
|
+
translator,
|
|
88
|
+
options.defaultPath
|
|
89
|
+
);
|
|
78
90
|
const dialogOptions: Partial<Dialog.IOptions<Contents.IModel[]>> = {
|
|
79
91
|
title: options.title,
|
|
80
92
|
buttons: [
|
|
@@ -86,8 +98,11 @@ export namespace FileDialog {
|
|
|
86
98
|
focusNodeSelector: options.focusNodeSelector,
|
|
87
99
|
host: options.host,
|
|
88
100
|
renderer: options.renderer,
|
|
89
|
-
body:
|
|
101
|
+
body: openDialog
|
|
90
102
|
};
|
|
103
|
+
|
|
104
|
+
await openDialog.ready;
|
|
105
|
+
|
|
91
106
|
const dialog = new Dialog(dialogOptions);
|
|
92
107
|
return dialog.launch();
|
|
93
108
|
}
|
|
@@ -125,6 +140,7 @@ class OpenDialog
|
|
|
125
140
|
manager: IDocumentManager,
|
|
126
141
|
filter?: (value: Contents.IModel) => Partial<IScore> | null,
|
|
127
142
|
translator?: ITranslator,
|
|
143
|
+
defaultPath?: string,
|
|
128
144
|
filterDirectories?: boolean
|
|
129
145
|
) {
|
|
130
146
|
super();
|
|
@@ -132,50 +148,63 @@ class OpenDialog
|
|
|
132
148
|
const trans = translator.load('jupyterlab');
|
|
133
149
|
this.addClass(OPEN_DIALOG_CLASS);
|
|
134
150
|
|
|
135
|
-
|
|
151
|
+
Private.createFilteredFileBrowser(
|
|
136
152
|
'filtered-file-browser-dialog',
|
|
137
153
|
manager,
|
|
138
154
|
filter,
|
|
139
155
|
{},
|
|
140
156
|
translator,
|
|
157
|
+
defaultPath,
|
|
141
158
|
filterDirectories
|
|
142
|
-
)
|
|
159
|
+
)
|
|
160
|
+
.then(browser => {
|
|
161
|
+
this._browser = browser;
|
|
143
162
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
name: 'refresher',
|
|
158
|
-
widget: new ToolbarButton({
|
|
159
|
-
icon: refreshIcon,
|
|
160
|
-
onClick: () => {
|
|
161
|
-
browser.model.refresh().catch(reason => {
|
|
162
|
-
console.error(
|
|
163
|
-
'Failed to refresh file browser in open dialog.',
|
|
164
|
-
reason
|
|
165
|
-
);
|
|
166
|
-
});
|
|
163
|
+
// Add toolbar items
|
|
164
|
+
setToolbar(this._browser, (browser: FileBrowser) => [
|
|
165
|
+
{
|
|
166
|
+
name: 'new-folder',
|
|
167
|
+
widget: new ToolbarButton({
|
|
168
|
+
icon: newFolderIcon,
|
|
169
|
+
onClick: () => {
|
|
170
|
+
void browser.createNewDirectory();
|
|
171
|
+
},
|
|
172
|
+
tooltip: trans.__('New Folder')
|
|
173
|
+
})
|
|
167
174
|
},
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
175
|
+
{
|
|
176
|
+
name: 'refresher',
|
|
177
|
+
widget: new ToolbarButton({
|
|
178
|
+
icon: refreshIcon,
|
|
179
|
+
onClick: () => {
|
|
180
|
+
browser.model.refresh().catch(reason => {
|
|
181
|
+
console.error(
|
|
182
|
+
'Failed to refresh file browser in open dialog.',
|
|
183
|
+
reason
|
|
184
|
+
);
|
|
185
|
+
});
|
|
186
|
+
},
|
|
187
|
+
tooltip: trans.__('Refresh File List')
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
]);
|
|
191
|
+
|
|
192
|
+
// Build the sub widgets
|
|
193
|
+
const layout = new PanelLayout();
|
|
194
|
+
layout.addWidget(this._browser);
|
|
172
195
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
layout.addWidget(this._browser);
|
|
196
|
+
// Set Widget content
|
|
197
|
+
this.layout = layout;
|
|
176
198
|
|
|
177
|
-
|
|
178
|
-
|
|
199
|
+
this._ready.resolve();
|
|
200
|
+
})
|
|
201
|
+
.catch(reason => {
|
|
202
|
+
console.error(
|
|
203
|
+
'Error while creating file browser in open dialog',
|
|
204
|
+
reason
|
|
205
|
+
);
|
|
206
|
+
this._ready.reject(void 0);
|
|
207
|
+
});
|
|
179
208
|
}
|
|
180
209
|
|
|
181
210
|
/**
|
|
@@ -203,6 +232,14 @@ class OpenDialog
|
|
|
203
232
|
}
|
|
204
233
|
}
|
|
205
234
|
|
|
235
|
+
/**
|
|
236
|
+
* A promise that resolves when openDialog is successfully created.
|
|
237
|
+
*/
|
|
238
|
+
get ready(): Promise<void> {
|
|
239
|
+
return this._ready.promise;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private _ready: PromiseDelegate<void> = new PromiseDelegate<void>();
|
|
206
243
|
private _browser: FileBrowser;
|
|
207
244
|
}
|
|
208
245
|
|
|
@@ -229,14 +266,15 @@ namespace Private {
|
|
|
229
266
|
* as the initial ID passed into the factory is used for only one file browser
|
|
230
267
|
* instance.
|
|
231
268
|
*/
|
|
232
|
-
export const createFilteredFileBrowser = (
|
|
269
|
+
export const createFilteredFileBrowser = async (
|
|
233
270
|
id: string,
|
|
234
271
|
manager: IDocumentManager,
|
|
235
272
|
filter?: (value: Contents.IModel) => Partial<IScore> | null,
|
|
236
273
|
options: IFileBrowserFactory.IOptions = {},
|
|
237
274
|
translator?: ITranslator,
|
|
275
|
+
defaultPath?: string,
|
|
238
276
|
filterDirectories?: boolean
|
|
239
|
-
): FileBrowser => {
|
|
277
|
+
): Promise<FileBrowser> => {
|
|
240
278
|
translator = translator || nullTranslator;
|
|
241
279
|
const model = new FilterFileBrowserModel({
|
|
242
280
|
manager,
|
|
@@ -246,6 +284,11 @@ namespace Private {
|
|
|
246
284
|
refreshInterval: options.refreshInterval,
|
|
247
285
|
filterDirectories
|
|
248
286
|
});
|
|
287
|
+
|
|
288
|
+
if (defaultPath) {
|
|
289
|
+
await model.cd(defaultPath);
|
|
290
|
+
}
|
|
291
|
+
|
|
249
292
|
const widget = new FileBrowser({
|
|
250
293
|
id,
|
|
251
294
|
model,
|