From 7e1bbc0cb557a71109f31e654fe4f3a0bb29bbc4 Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Sat, 2 Dec 2023 00:27:03 +0100 Subject: [PATCH] Remove the file actions toolbar, instead includes the action buttons in the file browser toolbar --- .../tree-extension/schema/file-actions.json | 9 +- packages/tree-extension/src/fileactions.tsx | 162 +++++++----------- packages/tree-extension/src/index.ts | 26 ++- packages/tree-extension/style/base.css | 16 +- 4 files changed, 86 insertions(+), 127 deletions(-) diff --git a/packages/tree-extension/schema/file-actions.json b/packages/tree-extension/schema/file-actions.json index 06fb441da7..90095879ca 100644 --- a/packages/tree-extension/schema/file-actions.json +++ b/packages/tree-extension/schema/file-actions.json @@ -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, diff --git a/packages/tree-extension/src/fileactions.tsx b/packages/tree-extension/src/fileactions.tsx index 87b03119bd..c70507810e 100644 --- a/packages/tree-extension/src/fileactions.tsx +++ b/packages/tree-extension/src/fileactions.tsx @@ -4,7 +4,6 @@ import { CommandToolbarButtonComponent, ReactWidget, - UseSignal, } from '@jupyterlab/apputils'; import { FileBrowser } from '@jupyterlab/filebrowser'; @@ -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
{trans.__('Select items to perform actions on them.')}
; - } 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; + translator: ITranslator; + }) { + this._browser = options.browser; + const { commands, selectionChanged, translator } = options; + const trans = translator.load('notebook'); - return ( - <> - {buttons.map((action) => ( - - ))} - + // Placeholder, when no file is selected. + const placeholder = ReactWidget.create( +
+ {trans.__('Select items to perform actions on them.')} +
); - } -}; + 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; - translator: ITranslator; -}): JSX.Element => { - return ( - true}> - {(): JSX.Element => ( - { + const widget = ReactWidget.create( + - )} - - ); -}; + ); + 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; - translator: ITranslator; - }): ReactWidget => { - const widget = ReactWidget.create( - - ); - widget.addClass('jp-FileActions'); - return widget; + get widgets(): IterableIterator { + 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(); } diff --git a/packages/tree-extension/src/index.ts b/packages/tree-extension/src/index.ts index 9593278afd..a4b58ad829 100644 --- a/packages/tree-extension/src/index.ts +++ b/packages/tree-extension/src/index.ts @@ -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. @@ -158,20 +158,16 @@ const fileActions: JupyterFrontEndPlugin = { // 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); + } }, }; diff --git a/packages/tree-extension/style/base.css b/packages/tree-extension/style/base.css index a0de64aaf0..7c2cf03249 100644 --- a/packages/tree-extension/style/base.css +++ b/packages/tree-extension/style/base.css @@ -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); }