Skip to content

Commit

Permalink
Remove the file actions toolbar, instead includes the action buttons …
Browse files Browse the repository at this point in the history
…in the file browser toolbar
  • Loading branch information
brichet committed Dec 3, 2023
1 parent a0931d0 commit 7e1bbc0
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 127 deletions.
9 changes: 8 additions & 1 deletion packages/tree-extension/schema/file-actions.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
"title": "File Browser Widget - File Actions",
"description": "File Browser widget - File Actions settings.",
"jupyter.lab.toolbars": {
"FileBrowser": [{ "name": "fileActions", "rank": 0 }]
"FileBrowser": [
{ "name": "fileAction-placeholder", "rank": 0 },
{ "name": "fileAction-open", "rank": 1 },
{ "name": "fileAction-download", "rank": 2 },
{ "name": "fileAction-rename", "rank": 3 },
{ "name": "fileAction-duplicate", "rank": 4 },
{ "name": "fileAction-delete", "rank": 5 }
]
},
"properties": {},
"additionalProperties": false,
Expand Down
162 changes: 61 additions & 101 deletions packages/tree-extension/src/fileactions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import {
CommandToolbarButtonComponent,
ReactWidget,
UseSignal,
} from '@jupyterlab/apputils';

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

import React from 'react';

/**
* A React component to display the list of command toolbar buttons.
*
*/
const Commands = ({
commands,
browser,
translator,
}: {
commands: CommandRegistry;
browser: FileBrowser;
translator: ITranslator;
}): JSX.Element => {
const trans = translator.load('notebook');
const selection = Array.from(browser.selectedItems());
const oneFolder = selection.some((item) => item.type === 'directory');
const multipleFiles =
selection.filter((item) => item.type === 'file').length > 1;
if (selection.length === 0) {
return <div>{trans.__('Select items to perform actions on them.')}</div>;
} else {
const buttons = ['delete'];
if (!oneFolder) {
buttons.unshift('duplicate');
if (!multipleFiles) {
buttons.unshift('rename');
}
buttons.unshift('download');
buttons.unshift('open');
} else if (selection.length === 1) {
buttons.unshift('rename');
}
export class FilesActionButtons {
/**
* The constructor of FilesActionButtons.
* @param options
*/
constructor(options: {
commands: CommandRegistry;
browser: FileBrowser;
selectionChanged: ISignal<FileBrowser, void>;
translator: ITranslator;
}) {
this._browser = options.browser;
const { commands, selectionChanged, translator } = options;
const trans = translator.load('notebook');

return (
<>
{buttons.map((action) => (
<CommandToolbarButtonComponent
key={action}
commands={commands}
id={`filebrowser:${action}`}
args={{ toolbar: true }}
icon={undefined}
/>
))}
</>
// Placeholder, when no file is selected.
const placeholder = ReactWidget.create(
<div key={'placeholder'}>
{trans.__('Select items to perform actions on them.')}
</div>
);
}
};
placeholder.id = 'fileAction-placeholder';
this._widgets.set('placeholder', placeholder);

/**
* A React component to display the file action buttons in the file browser toolbar.
*
* @param translator The Translation service
*/
const FileActions = ({
commands,
browser,
selectionChanged,
translator,
}: {
commands: CommandRegistry;
browser: FileBrowser;
selectionChanged: ISignal<FileBrowser, void>;
translator: ITranslator;
}): JSX.Element => {
return (
<UseSignal signal={selectionChanged} shouldUpdate={() => true}>
{(): JSX.Element => (
<Commands
// The action buttons.
const actions = ['open', 'download', 'rename', 'duplicate', 'delete'];
actions.forEach((action) => {
const widget = ReactWidget.create(
<CommandToolbarButtonComponent
key={action}
commands={commands}
browser={browser}
translator={translator}
id={`filebrowser:${action}`}
args={{ toolbar: true }}
icon={undefined}
/>
)}
</UseSignal>
);
};
);
widget.id = `fileAction-${action}`;
widget.addClass('jp-FileAction');
this._widgets.set(action, widget);
});

selectionChanged.connect(this._onSelectionChanged, this);
this._onSelectionChanged();
}

/**
* A namespace for FileActionsComponent static functions.
*/
export namespace FileActionsComponent {
/**
* Create a new FileActionsComponent
*
* @param translator The translator
* Return an iterator with all the action widgets.
*/
export const create = ({
commands,
browser,
selectionChanged,
translator,
}: {
commands: CommandRegistry;
browser: FileBrowser;
selectionChanged: ISignal<FileBrowser, void>;
translator: ITranslator;
}): ReactWidget => {
const widget = ReactWidget.create(
<FileActions
commands={commands}
browser={browser}
selectionChanged={selectionChanged}
translator={translator}
/>
);
widget.addClass('jp-FileActions');
return widget;
get widgets(): IterableIterator<ReactWidget> {
return this._widgets.values();
}

/**
* Triggered when the selection change in file browser.
*/
private _onSelectionChanged = () => {
const selectedItems = Array.from(this._browser.selectedItems());
const selection = selectedItems.length > 0;
const oneFolder = selectedItems.some((item) => item.type === 'directory');

this._widgets.get('placeholder')?.setHidden(selection);
this._widgets.get('delete')?.setHidden(!selection);
this._widgets.get('duplicate')?.setHidden(!selection || oneFolder);
this._widgets.get('download')?.setHidden(!selection || oneFolder);
this._widgets.get('open')?.setHidden(!selection || oneFolder);
this._widgets.get('rename')?.setHidden(selectedItems.length !== 1);
};

private _browser: FileBrowser;
private _widgets = new Map<string, ReactWidget>();
}
26 changes: 11 additions & 15 deletions packages/tree-extension/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import { Menu, MenuBar } from '@lumino/widgets';

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

import { FileActionsComponent } from './fileactions';
import { FilesActionButtons } from './fileactions';

/**
* The file browser factory.
Expand Down Expand Up @@ -158,20 +158,16 @@ const fileActions: JupyterFrontEndPlugin<void> = {

// Create a toolbar item that adds buttons to the file browser toolbar
// to perform actions on the files
toolbarRegistry.addFactory(
FILE_BROWSER_FACTORY,
'fileActions',
(browser: FileBrowser) => {
const { commands } = app;
const fileActions = FileActionsComponent.create({
commands,
browser,
selectionChanged,
translator,
});
return fileActions;
}
);
const { commands } = app;
const fileActions = new FilesActionButtons({
commands,
browser,
selectionChanged,
translator,
});
for (const widget of fileActions.widgets) {
toolbarRegistry.addFactory(FILE_BROWSER_FACTORY, widget.id, () => widget);
}
},
};

Expand Down
16 changes: 6 additions & 10 deletions packages/tree-extension/style/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,23 @@

/* Action buttons */

.jp-FileBrowser-toolbar > .jp-FileActions.jp-Toolbar-item {
display: flex;
flex-direction: row;
}

.jp-FileActions .jp-ToolbarButtonComponent-icon {
.jp-FileBrowser-toolbar > .jp-FileAction > .jp-ToolbarButtonComponent > svg {
display: none;
}

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

.jp-FileActions
.jp-FileBrowser-toolbar
.jp-ToolbarButtonComponent[data-command='filebrowser:delete']
.jp-ToolbarButtonComponent-label {
color: var(--jp-ui-inverse-font-color1);
}

.jp-FileBrowser-toolbar .jp-FileActions .jp-ToolbarButtonComponent {
.jp-FileBrowser-toolbar .jp-FileAction {
border: solid 1px var(--jp-border-color2);
margin: 1px;
min-height: 100%;
min-height: var(--jp-private-toolbar-height);
}

0 comments on commit 7e1bbc0

Please sign in to comment.