Skip to content

Commit 78275a3

Browse files
committed
Make file browser respond to focussed elements
1 parent dd944be commit 78275a3

File tree

7 files changed

+1040
-251
lines changed

7 files changed

+1040
-251
lines changed

packages/filebrowser-extension/schema/browser.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,6 @@
157157
"keys": ["Accel Shift F"],
158158
"selector": "body"
159159
},
160-
{
161-
"command": "filebrowser:go-up",
162-
"keys": ["Backspace"],
163-
"selector": ".jp-DirListing-content .jp-DirListing-itemText"
164-
},
165160
{
166161
"command": "filebrowser:delete",
167162
"keys": ["Delete"],

packages/filebrowser-extension/src/index.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,11 @@ const downloadPlugin: JupyterFrontEndPlugin<void> = {
365365
Clipboard.copyToSystem(url);
366366
});
367367
},
368+
isVisible: () =>
369+
// So long as this command only handles one file at time, don't show it
370+
// if multiple files are selected.
371+
!!tracker.currentWidget &&
372+
Array.from(tracker.currentWidget.selectedItems()).length === 1,
368373
icon: copyIcon.bindprops({ stylesheet: 'menuItem' }),
369374
label: trans.__('Copy Download Link'),
370375
mnemonic: 0
@@ -890,14 +895,8 @@ function addCommands(
890895
if (model.path === model.rootPath) {
891896
return;
892897
}
893-
try {
894-
await model.cd('..');
895-
} catch (reason) {
896-
console.warn(
897-
`${CommandIDs.goUp} failed to go to parent directory of ${model.path}`,
898-
reason
899-
);
900-
}
898+
899+
browserForPath.goUp();
901900
}
902901
});
903902

@@ -1076,6 +1075,11 @@ function addCommands(
10761075
return widget.rename();
10771076
}
10781077
},
1078+
isVisible: () =>
1079+
// So long as this command only handles one file at time, don't show it
1080+
// if multiple files are selected.
1081+
!!tracker.currentWidget &&
1082+
Array.from(tracker.currentWidget.selectedItems()).length === 1,
10791083
icon: editIcon.bindprops({ stylesheet: 'menuItem' }),
10801084
label: trans.__('Rename'),
10811085
mnemonic: 0
@@ -1095,8 +1099,10 @@ function addCommands(
10951099
Clipboard.copyToSystem(item.value.path);
10961100
},
10971101
isVisible: () =>
1102+
// So long as this command only handles one file at time, don't show it
1103+
// if multiple files are selected.
10981104
!!tracker.currentWidget &&
1099-
!tracker.currentWidget.selectedItems().next().done,
1105+
Array.from(tracker.currentWidget.selectedItems()).length === 1,
11001106
icon: fileIcon.bindprops({ stylesheet: 'menuItem' }),
11011107
label: trans.__('Copy Path')
11021108
});

packages/filebrowser/src/browser.ts

Lines changed: 70 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ export class FileBrowser extends SidePanel {
7979
this._trans.__('file browser')
8080
);
8181

82-
this._directoryPending = false;
83-
8482
// File browser widgets container
8583
this.mainPanel = new Panel();
8684
this.mainPanel.addClass(FILE_BROWSER_PANEL_CLASS);
@@ -263,63 +261,52 @@ export class FileBrowser extends SidePanel {
263261
return this.listing.paste();
264262
}
265263

266-
/**
267-
* Create a new directory
268-
*/
269-
createNewDirectory(): void {
270-
if (this._directoryPending === true) {
271-
return;
264+
private _createNew(
265+
future: Private.FutureNewDirectoryItem,
266+
createOptions: Contents.ICreateOptions
267+
): Promise<Contents.IModel> {
268+
if (future.pending === true) {
269+
return future.promise;
272270
}
273-
this._directoryPending = true;
274-
// TODO: We should provide a hook into when the
275-
// directory is done being created. This probably
276-
// means storing a pendingDirectory promise and
277-
// returning that if there is already a directory
278-
// request.
279-
void this._manager
280-
.newUntitled({
281-
path: this.model.path,
282-
type: 'directory'
283-
})
284-
.then(async model => {
285-
await this.listing.selectItemByName(model.name);
271+
const newItem = {
272+
pending: true,
273+
promise: this._manager.newUntitled(createOptions).then(async model => {
274+
await this.listing.selectItemByName(model.name, true);
286275
await this.rename();
287-
this._directoryPending = false;
276+
return model;
288277
})
278+
};
279+
Object.assign(future, newItem);
280+
const { promise } = newItem;
281+
promise
289282
.catch(err => {
290283
void showErrorMessage(this._trans.__('Error'), err);
291-
this._directoryPending = false;
284+
})
285+
.finally(() => {
286+
future.pending = false;
292287
});
288+
return promise;
289+
}
290+
291+
/**
292+
* Create a new directory
293+
*/
294+
createNewDirectory(): Promise<Contents.IModel> {
295+
return this._createNew(this._futureNewDirectory, {
296+
path: this.model.path,
297+
type: 'directory'
298+
});
293299
}
294300

295301
/**
296302
* Create a new file
297303
*/
298-
createNewFile(options: FileBrowser.IFileOptions): void {
299-
if (this._filePending === true) {
300-
return;
301-
}
302-
this._filePending = true;
303-
// TODO: We should provide a hook into when the
304-
// file is done being created. This probably
305-
// means storing a pendingFile promise and
306-
// returning that if there is already a file
307-
// request.
308-
void this._manager
309-
.newUntitled({
310-
path: this.model.path,
311-
type: 'file',
312-
ext: options.ext
313-
})
314-
.then(async model => {
315-
await this.listing.selectItemByName(model.name);
316-
await this.rename();
317-
this._filePending = false;
318-
})
319-
.catch(err => {
320-
void showErrorMessage(this._trans.__('Error'), err);
321-
this._filePending = false;
322-
});
304+
createNewFile(options: FileBrowser.IFileOptions): Promise<Contents.IModel> {
305+
return this._createNew(this._futureNewFile, {
306+
path: this.model.path,
307+
type: 'file',
308+
ext: options.ext
309+
});
323310
}
324311

325312
/**
@@ -347,6 +334,15 @@ export class FileBrowser extends SidePanel {
347334
return this.listing.download();
348335
}
349336

337+
/**
338+
* cd ..
339+
*
340+
* Go up one level in the directory tree.
341+
*/
342+
async goUp() {
343+
return this.listing.goUp();
344+
}
345+
350346
/**
351347
* Shut down kernels on the applicable currently selected items.
352348
*
@@ -420,8 +416,14 @@ export class FileBrowser extends SidePanel {
420416

421417
private _filenameSearcher: ReactWidget;
422418
private _manager: IDocumentManager;
423-
private _directoryPending: boolean;
424-
private _filePending: boolean;
419+
private _futureNewDirectory: Private.FutureNewDirectoryItem = {
420+
pending: false,
421+
promise: null
422+
};
423+
private _futureNewFile: Private.FutureNewDirectoryItem = {
424+
pending: false,
425+
promise: null
426+
};
425427
private _navigateToCurrentDirectory: boolean;
426428
private _showLastModifiedColumn: boolean = true;
427429
private _useFuzzyFilter: boolean = true;
@@ -480,3 +482,21 @@ export namespace FileBrowser {
480482
ext: string;
481483
}
482484
}
485+
486+
namespace Private {
487+
/**
488+
* A special type with the following properties:
489+
* - When `pending` is `true`, the `promise` field points to a promise for a
490+
* new directory or file.
491+
* - When `pending` is `false`, the `promise` field has no guarantee.
492+
*/
493+
export type FutureNewDirectoryItem =
494+
| {
495+
pending: true;
496+
promise: Promise<Contents.IModel>;
497+
}
498+
| {
499+
pending: false;
500+
promise: any;
501+
};
502+
}

0 commit comments

Comments
 (0)