-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make file browser respond to focussed elements #13577
Changes from 36 commits
1879719
56bb994
89275eb
1ba8ead
798a761
b9fac45
942dcf3
62ade7f
1f79c74
976cf25
1e10b87
e14210e
b79602f
81b30d7
3486214
8f8a562
1fe9396
d9edb05
edb3e0f
3f1fc1b
67754d5
ce360b7
fd11744
9d41cd8
4964bdd
1825188
bdf0525
37663ad
27b17b5
63ef7cf
1ce98ba
0ec939a
70266d5
c762fe1
f7dffae
4e7f36b
91408e2
7a2f007
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -136,6 +136,11 @@ | |
"title": "File Browser", | ||
"description": "File Browser settings.", | ||
"jupyter.lab.shortcuts": [ | ||
{ | ||
"command": "filebrowser:go-up", | ||
"keys": ["Backspace"], | ||
"selector": ".jp-DirListing:focus" | ||
}, | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved backspace handling into the DirListing class. You can reason from the way it's configured here that it doesn't work if the directory is empty, because if it's empty there is no |
||
"command": "filebrowser:go-up", | ||
"keys": ["Backspace"], | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -375,6 +375,11 @@ const downloadPlugin: JupyterFrontEndPlugin<void> = { | |
Clipboard.copyToSystem(url); | ||
}); | ||
}, | ||
isVisible: () => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The "copy download link" command does not accept multiple files, so do not show it in the (right-click) context menu when multiple files are selected. |
||
// So long as this command only handles one file at time, don't show it | ||
// if multiple files are selected. | ||
!!tracker.currentWidget && | ||
Array.from(tracker.currentWidget.selectedItems()).length === 1, | ||
icon: copyIcon.bindprops({ stylesheet: 'menuItem' }), | ||
label: trans.__('Copy Download Link'), | ||
mnemonic: 0 | ||
|
@@ -986,19 +991,8 @@ function addCommands( | |
return; | ||
} | ||
const { model } = browserForPath; | ||
|
||
await model.restored; | ||
if (model.path === model.rootPath) { | ||
return; | ||
} | ||
try { | ||
await model.cd('..'); | ||
} catch (reason) { | ||
console.warn( | ||
`${CommandIDs.goUp} failed to go to parent directory of ${model.path}`, | ||
reason | ||
); | ||
} | ||
void browserForPath.goUp(); | ||
} | ||
}); | ||
|
||
|
@@ -1181,6 +1175,11 @@ function addCommands( | |
return widget.rename(); | ||
} | ||
}, | ||
isVisible: () => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no batch, multi-file "rename" command, so do not show it in the (right-click) context menu when multiple files are selected. |
||
// So long as this command only handles one file at time, don't show it | ||
// if multiple files are selected. | ||
!!tracker.currentWidget && | ||
Array.from(tracker.currentWidget.selectedItems()).length === 1, | ||
icon: editIcon.bindprops({ stylesheet: 'menuItem' }), | ||
label: trans.__('Rename'), | ||
mnemonic: 0 | ||
|
@@ -1200,8 +1199,10 @@ function addCommands( | |
Clipboard.copyToSystem(item.value.path); | ||
}, | ||
isVisible: () => | ||
// So long as this command only handles one file at time, don't show it | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The "copy path" command does not support multiple files, so do not show it in the (right-click) context menu when multiple files are selected. Note: in Windows, when multiple files are selected, the copy-path command puts each path on a newline in the clipboard. |
||
// if multiple files are selected. | ||
!!tracker.currentWidget && | ||
!tracker.currentWidget.selectedItems().next().done, | ||
Array.from(tracker.currentWidget.selectedItems()).length === 1, | ||
icon: fileIcon.bindprops({ stylesheet: 'menuItem' }), | ||
label: trans.__('Copy Path') | ||
}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,8 +69,6 @@ export class FileBrowser extends SidePanel { | |
this._trans.__('file browser') | ||
); | ||
|
||
this._directoryPending = false; | ||
|
||
// File browser widgets container | ||
this.mainPanel = new Panel(); | ||
this.mainPanel.addClass(FILE_BROWSER_PANEL_CLASS); | ||
|
@@ -226,63 +224,57 @@ export class FileBrowser extends SidePanel { | |
return this.listing.paste(); | ||
} | ||
|
||
private async _createNew( | ||
options: Contents.ICreateOptions | ||
): Promise<Contents.IModel> { | ||
try { | ||
const model = await this._manager.newUntitled(options); | ||
await this.listing.selectItemByName(model.name, true); | ||
await this.rename(); | ||
return model; | ||
} catch (err) { | ||
void showErrorMessage(this._trans.__('Error'), err); | ||
throw err; | ||
} | ||
} | ||
|
||
/** | ||
* Create a new directory | ||
*/ | ||
createNewDirectory(): void { | ||
if (this._directoryPending === true) { | ||
return; | ||
async createNewDirectory(): Promise<Contents.IModel> { | ||
if (this._directoryPending) { | ||
return this._directoryPending; | ||
} | ||
this._directoryPending = this._createNew({ | ||
path: this.model.path, | ||
type: 'directory' | ||
}); | ||
try { | ||
return await this._directoryPending; | ||
} finally { | ||
this._directoryPending = null; | ||
} | ||
this._directoryPending = true; | ||
// TODO: We should provide a hook into when the | ||
// directory is done being created. This probably | ||
// means storing a pendingDirectory promise and | ||
// returning that if there is already a directory | ||
// request. | ||
void this._manager | ||
.newUntitled({ | ||
path: this.model.path, | ||
type: 'directory' | ||
}) | ||
.then(async model => { | ||
await this.listing.selectItemByName(model.name); | ||
await this.rename(); | ||
this._directoryPending = false; | ||
}) | ||
.catch(err => { | ||
void showErrorMessage(this._trans.__('Error'), err); | ||
this._directoryPending = false; | ||
}); | ||
} | ||
|
||
/** | ||
* Create a new file | ||
*/ | ||
createNewFile(options: FileBrowser.IFileOptions): void { | ||
if (this._filePending === true) { | ||
return; | ||
async createNewFile( | ||
options: FileBrowser.IFileOptions | ||
): Promise<Contents.IModel> { | ||
if (this._filePending) { | ||
return this._filePending; | ||
} | ||
this._filePending = this._createNew({ | ||
path: this.model.path, | ||
type: 'file', | ||
ext: options.ext | ||
}); | ||
try { | ||
return await this._filePending; | ||
} finally { | ||
this._filePending = null; | ||
} | ||
this._filePending = true; | ||
// TODO: We should provide a hook into when the | ||
// file is done being created. This probably | ||
// means storing a pendingFile promise and | ||
// returning that if there is already a file | ||
// request. | ||
void this._manager | ||
.newUntitled({ | ||
path: this.model.path, | ||
type: 'file', | ||
ext: options.ext | ||
}) | ||
.then(async model => { | ||
await this.listing.selectItemByName(model.name); | ||
await this.rename(); | ||
this._filePending = false; | ||
}) | ||
.catch(err => { | ||
void showErrorMessage(this._trans.__('Error'), err); | ||
this._filePending = false; | ||
}); | ||
} | ||
|
||
/** | ||
|
@@ -310,6 +302,15 @@ export class FileBrowser extends SidePanel { | |
return this.listing.download(); | ||
} | ||
|
||
/** | ||
* cd .. | ||
* | ||
* Go up one level in the directory tree. | ||
*/ | ||
async goUp() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
return this.listing.goUp(); | ||
} | ||
|
||
/** | ||
* Shut down kernels on the applicable currently selected items. | ||
* | ||
|
@@ -382,8 +383,8 @@ export class FileBrowser extends SidePanel { | |
protected mainPanel: Panel; | ||
|
||
private _manager: IDocumentManager; | ||
private _directoryPending: boolean; | ||
private _filePending: boolean; | ||
private _directoryPending: Promise<Contents.IModel> | null = null; | ||
private _filePending: Promise<Contents.IModel> | null = null; | ||
private _navigateToCurrentDirectory: boolean; | ||
private _showLastModifiedColumn: boolean = true; | ||
private _showFileSizeColumn: boolean = false; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, this seems to do the trick: just add another selector to handle the case when the directory is empty and leave the other selector alone. I wish I could leave a comment in this JSON file.
This
:focus
selector works for when the directory is empty because the only node (within the directory listing widget) that can receive focus at that point is the directory listing node itself. We cannot use the selector without:focus
though because then it would get triggered if the user were in the middle of renaming a file, makes a typo, and then presses backspace to delete the typo.I tested this change three ways: