Skip to content

Commit 763111e

Browse files
committed
Remove the file actions toolbar, instead includes the action buttons in the file browser toolbar
1 parent 2e851eb commit 763111e

File tree

4 files changed

+86
-127
lines changed

4 files changed

+86
-127
lines changed

packages/tree-extension/schema/file-actions.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22
"title": "File Browser Widget - File Actions",
33
"description": "File Browser widget - File Actions settings.",
44
"jupyter.lab.toolbars": {
5-
"FileBrowser": [{ "name": "fileActions", "rank": 0 }]
5+
"FileBrowser": [
6+
{ "name": "fileAction-placeholder", "rank": 0 },
7+
{ "name": "fileAction-open", "rank": 1 },
8+
{ "name": "fileAction-download", "rank": 2 },
9+
{ "name": "fileAction-rename", "rank": 3 },
10+
{ "name": "fileAction-duplicate", "rank": 4 },
11+
{ "name": "fileAction-delete", "rank": 5 }
12+
]
613
},
714
"properties": {},
815
"additionalProperties": false,

packages/tree-extension/src/fileactions.tsx

Lines changed: 61 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import {
55
CommandToolbarButtonComponent,
66
ReactWidget,
7-
UseSignal,
87
} from '@jupyterlab/apputils';
98

109
import { FileBrowser } from '@jupyterlab/filebrowser';
@@ -17,113 +16,74 @@ import { ISignal } from '@lumino/signaling';
1716

1817
import React from 'react';
1918

20-
/**
21-
* A React component to display the list of command toolbar buttons.
22-
*
23-
*/
24-
const Commands = ({
25-
commands,
26-
browser,
27-
translator,
28-
}: {
29-
commands: CommandRegistry;
30-
browser: FileBrowser;
31-
translator: ITranslator;
32-
}): JSX.Element => {
33-
const trans = translator.load('notebook');
34-
const selection = Array.from(browser.selectedItems());
35-
const oneFolder = selection.some((item) => item.type === 'directory');
36-
const multipleFiles =
37-
selection.filter((item) => item.type === 'file').length > 1;
38-
if (selection.length === 0) {
39-
return <div>{trans.__('Select items to perform actions on them.')}</div>;
40-
} else {
41-
const buttons = ['delete'];
42-
if (!oneFolder) {
43-
buttons.unshift('duplicate');
44-
if (!multipleFiles) {
45-
buttons.unshift('rename');
46-
}
47-
buttons.unshift('download');
48-
buttons.unshift('open');
49-
} else if (selection.length === 1) {
50-
buttons.unshift('rename');
51-
}
19+
export class FilesActionButtons {
20+
/**
21+
* The constructor of FilesActionButtons.
22+
* @param options
23+
*/
24+
constructor(options: {
25+
commands: CommandRegistry;
26+
browser: FileBrowser;
27+
selectionChanged: ISignal<FileBrowser, void>;
28+
translator: ITranslator;
29+
}) {
30+
this._browser = options.browser;
31+
const { commands, selectionChanged, translator } = options;
32+
const trans = translator.load('notebook');
5233

53-
return (
54-
<>
55-
{buttons.map((action) => (
56-
<CommandToolbarButtonComponent
57-
key={action}
58-
commands={commands}
59-
id={`filebrowser:${action}`}
60-
args={{ toolbar: true }}
61-
icon={undefined}
62-
/>
63-
))}
64-
</>
34+
// Placeholder, when no file is selected.
35+
const placeholder = ReactWidget.create(
36+
<div key={'placeholder'}>
37+
{trans.__('Select items to perform actions on them.')}
38+
</div>
6539
);
66-
}
67-
};
40+
placeholder.id = 'fileAction-placeholder';
41+
this._widgets.set('placeholder', placeholder);
6842

69-
/**
70-
* A React component to display the file action buttons in the file browser toolbar.
71-
*
72-
* @param translator The Translation service
73-
*/
74-
const FileActions = ({
75-
commands,
76-
browser,
77-
selectionChanged,
78-
translator,
79-
}: {
80-
commands: CommandRegistry;
81-
browser: FileBrowser;
82-
selectionChanged: ISignal<FileBrowser, void>;
83-
translator: ITranslator;
84-
}): JSX.Element => {
85-
return (
86-
<UseSignal signal={selectionChanged} shouldUpdate={() => true}>
87-
{(): JSX.Element => (
88-
<Commands
43+
// The action buttons.
44+
const actions = ['open', 'download', 'rename', 'duplicate', 'delete'];
45+
actions.forEach((action) => {
46+
const widget = ReactWidget.create(
47+
<CommandToolbarButtonComponent
48+
key={action}
8949
commands={commands}
90-
browser={browser}
91-
translator={translator}
50+
id={`filebrowser:${action}`}
51+
args={{ toolbar: true }}
52+
icon={undefined}
9253
/>
93-
)}
94-
</UseSignal>
95-
);
96-
};
54+
);
55+
widget.id = `fileAction-${action}`;
56+
widget.addClass('jp-FileAction');
57+
this._widgets.set(action, widget);
58+
});
59+
60+
selectionChanged.connect(this._onSelectionChanged, this);
61+
this._onSelectionChanged();
62+
}
9763

98-
/**
99-
* A namespace for FileActionsComponent static functions.
100-
*/
101-
export namespace FileActionsComponent {
10264
/**
103-
* Create a new FileActionsComponent
104-
*
105-
* @param translator The translator
65+
* Return an iterator with all the action widgets.
10666
*/
107-
export const create = ({
108-
commands,
109-
browser,
110-
selectionChanged,
111-
translator,
112-
}: {
113-
commands: CommandRegistry;
114-
browser: FileBrowser;
115-
selectionChanged: ISignal<FileBrowser, void>;
116-
translator: ITranslator;
117-
}): ReactWidget => {
118-
const widget = ReactWidget.create(
119-
<FileActions
120-
commands={commands}
121-
browser={browser}
122-
selectionChanged={selectionChanged}
123-
translator={translator}
124-
/>
125-
);
126-
widget.addClass('jp-FileActions');
127-
return widget;
67+
get widgets(): IterableIterator<ReactWidget> {
68+
return this._widgets.values();
69+
}
70+
71+
/**
72+
* Triggered when the selection change in file browser.
73+
*/
74+
private _onSelectionChanged = () => {
75+
const selectedItems = Array.from(this._browser.selectedItems());
76+
const selection = selectedItems.length > 0;
77+
const oneFolder = selectedItems.some((item) => item.type === 'directory');
78+
79+
this._widgets.get('placeholder')?.setHidden(selection);
80+
this._widgets.get('delete')?.setHidden(!selection);
81+
this._widgets.get('duplicate')?.setHidden(!selection || oneFolder);
82+
this._widgets.get('download')?.setHidden(!selection || oneFolder);
83+
this._widgets.get('open')?.setHidden(!selection || oneFolder);
84+
this._widgets.get('rename')?.setHidden(selectedItems.length !== 1);
12885
};
86+
87+
private _browser: FileBrowser;
88+
private _widgets = new Map<string, ReactWidget>();
12989
}

packages/tree-extension/src/index.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import { Menu, MenuBar } from '@lumino/widgets';
4545

4646
import { NotebookTreeWidget, INotebookTree } from '@jupyter-notebook/tree';
4747

48-
import { FileActionsComponent } from './fileactions';
48+
import { FilesActionButtons } from './fileactions';
4949

5050
/**
5151
* The file browser factory.
@@ -158,20 +158,16 @@ const fileActions: JupyterFrontEndPlugin<void> = {
158158

159159
// Create a toolbar item that adds buttons to the file browser toolbar
160160
// to perform actions on the files
161-
toolbarRegistry.addFactory(
162-
FILE_BROWSER_FACTORY,
163-
'fileActions',
164-
(browser: FileBrowser) => {
165-
const { commands } = app;
166-
const fileActions = FileActionsComponent.create({
167-
commands,
168-
browser,
169-
selectionChanged,
170-
translator,
171-
});
172-
return fileActions;
173-
}
174-
);
161+
const { commands } = app;
162+
const fileActions = new FilesActionButtons({
163+
commands,
164+
browser,
165+
selectionChanged,
166+
translator,
167+
});
168+
for (const widget of fileActions.widgets) {
169+
toolbarRegistry.addFactory(FILE_BROWSER_FACTORY, widget.id, () => widget);
170+
}
175171
},
176172
};
177173

packages/tree-extension/style/base.css

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,23 @@
3131

3232
/* Action buttons */
3333

34-
.jp-FileBrowser-toolbar > .jp-FileActions.jp-Toolbar-item {
35-
display: flex;
36-
flex-direction: row;
37-
}
38-
39-
.jp-FileActions .jp-ToolbarButtonComponent-icon {
34+
.jp-FileBrowser-toolbar > .jp-FileAction > .jp-ToolbarButtonComponent > svg {
4035
display: none;
4136
}
4237

43-
.jp-FileActions .jp-ToolbarButtonComponent[data-command='filebrowser:delete'] {
38+
.jp-FileBrowser-toolbar
39+
.jp-FileAction:has(> .jp-ToolbarButtonComponent[data-command='filebrowser:delete']) {
4440
background-color: var(--jp-error-color1);
4541
}
4642

47-
.jp-FileActions
43+
.jp-FileBrowser-toolbar
4844
.jp-ToolbarButtonComponent[data-command='filebrowser:delete']
4945
.jp-ToolbarButtonComponent-label {
5046
color: var(--jp-ui-inverse-font-color1);
5147
}
5248

53-
.jp-FileBrowser-toolbar .jp-FileActions .jp-ToolbarButtonComponent {
49+
.jp-FileBrowser-toolbar .jp-FileAction {
5450
border: solid 1px var(--jp-border-color2);
5551
margin: 1px;
56-
min-height: 100%;
52+
min-height: var(--jp-private-toolbar-height);
5753
}

0 commit comments

Comments
 (0)