From 2a1f819e4cfbbbcee702beb8413534751dce91cf Mon Sep 17 00:00:00 2001 From: Sven Efftinge Date: Tue, 8 Oct 2019 07:25:49 +0000 Subject: [PATCH] [plugin] tree view improvements - handle undefined treeItem.label - better styling for item actions - support descriptions - fix color for inactive selections (layout (grey) not accent (blue)) - don't execute command on selection change Signed-off-by: Sven Efftinge --- packages/core/src/browser/style/tree.css | 2 +- .../plugin-ext/src/common/plugin-api-rpc.ts | 4 ++- .../src/main/browser/style/tree.css | 14 ++++++-- .../main/browser/view/tree-view-widget.tsx | 35 ++++++++++++++++--- .../src/main/browser/view/tree-views-main.ts | 10 +----- .../plugin-ext/src/plugin/tree/tree-views.ts | 7 ++-- packages/plugin/src/theia.d.ts | 6 ++++ 7 files changed, 55 insertions(+), 23 deletions(-) diff --git a/packages/core/src/browser/style/tree.css b/packages/core/src/browser/style/tree.css index a63c76227df76..bdd4842c18ccd 100644 --- a/packages/core/src/browser/style/tree.css +++ b/packages/core/src/browser/style/tree.css @@ -87,7 +87,7 @@ } .theia-Tree .theia-TreeNode.theia-mod-selected { - background: var(--theia-accent-color4); + background: var(--theia-layout-color4); } .theia-TreeNode.theia-mod-not-selectable { diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts index 4e26732589478..b315440bebe8f 100644 --- a/packages/plugin-ext/src/common/plugin-api-rpc.ts +++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts @@ -493,12 +493,14 @@ export interface TreeViewsExt { $setVisible(treeViewId: string, visible: boolean): Promise; } -export class TreeViewItem { +export interface TreeViewItem { id: string; label: string; + description?: string; + /* font-awesome icon for compatibility */ icon?: string; iconUrl?: IconUrl; diff --git a/packages/plugin-ext/src/main/browser/style/tree.css b/packages/plugin-ext/src/main/browser/style/tree.css index 551a292d20fce..71e9184520462 100644 --- a/packages/plugin-ext/src/main/browser/style/tree.css +++ b/packages/plugin-ext/src/main/browser/style/tree.css @@ -29,9 +29,17 @@ } .theia-tree-view-inline-action { - background-size: 22px !important; - width: 22px !important; - height: 22px !important; + padding: 2px; +} + +.theia-tree-view-description { + color: var(--theia-ui-font-color2); + font-size: var(--theia-ui-font-size0); + margin-left: var(--theia-ui-padding); +} + +.theia-TreeNodeSegment { + display: flex; } .theia-tree-view .theia-TreeNodeContent { diff --git a/packages/plugin-ext/src/main/browser/view/tree-view-widget.tsx b/packages/plugin-ext/src/main/browser/view/tree-view-widget.tsx index 3a5dfa2c5dbd3..d739cc07b5f86 100644 --- a/packages/plugin-ext/src/main/browser/view/tree-view-widget.tsx +++ b/packages/plugin-ext/src/main/browser/view/tree-view-widget.tsx @@ -125,7 +125,8 @@ export class PluginTree extends TreeImpl { const update = { name: item.label, icon, - description: item.tooltip, + description: item.description, + tooltip: item.tooltip, contextValue: item.contextValue }; const node = this.getNode(item.id); @@ -242,7 +243,7 @@ export class TreeViewWidget extends TreeWidget { if (node.description) { attrs = { ...attrs, - title: node.description + title: 'tooltip' in node ? node['tooltip'] : '' }; } @@ -253,10 +254,10 @@ export class TreeViewWidget extends TreeWidget { protected getCaption(node: TreeNode): React.ReactNode[] { const nodes: React.ReactNode[] = []; - let work = node.name; + let work = node.name || ''; const regex = /\[([^\[]+)\]\(([^\)]+)\)/g; - const matchResult = node.name.match(regex); + const matchResult = work.match(regex); if (matchResult) { matchResult.forEach(match => { @@ -274,7 +275,12 @@ export class TreeViewWidget extends TreeWidget { }); } - nodes.push(work); + nodes.push(
{work}
); + if (node.description) { + nodes.push(
+ {node.description} +
); + } return nodes; } @@ -340,4 +346,23 @@ export class TreeViewWidget extends TreeWidget { } } + handleEnter(event: KeyboardEvent): void { + super.handleEnter(event); + this.tryExecuteCommand(); + } + + handleClickEvent(node: TreeNode, event: React.MouseEvent): void { + super.handleClickEvent(node, event); + this.tryExecuteCommand(node); + } + + // execute TreeItem.command if present + protected tryExecuteCommand(node?: TreeNode): void { + const treeNodes = (node ? [node] : this.model.selectedNodes) as TreeViewNode[]; + for (const treeNode of treeNodes) { + if (treeNode && treeNode.command) { + this.commands.executeCommand(treeNode.command.id, ...(treeNode.command.arguments || [])); + } + } + } } diff --git a/packages/plugin-ext/src/main/browser/view/tree-views-main.ts b/packages/plugin-ext/src/main/browser/view/tree-views-main.ts index f9864c0d3a35f..48d82d4bea1ed 100644 --- a/packages/plugin-ext/src/main/browser/view/tree-views-main.ts +++ b/packages/plugin-ext/src/main/browser/view/tree-views-main.ts @@ -20,7 +20,7 @@ import { RPCProtocol } from '../../../common/rpc-protocol'; import { PluginViewRegistry, PLUGIN_VIEW_DATA_FACTORY_ID } from './plugin-view-registry'; import { SelectableTreeNode, ExpandableTreeNode, CompositeTreeNode, WidgetManager } from '@theia/core/lib/browser'; import { ViewContextKeyService } from './view-context-key-service'; -import { CommandRegistry, Disposable, DisposableCollection } from '@theia/core'; +import { Disposable, DisposableCollection } from '@theia/core'; import { TreeViewWidget, TreeViewNode } from './tree-view-widget'; export class TreeViewsMainImpl implements TreeViewsMain, Disposable { @@ -28,7 +28,6 @@ export class TreeViewsMainImpl implements TreeViewsMain, Disposable { private readonly proxy: TreeViewsExt; private readonly viewRegistry: PluginViewRegistry; private readonly contextKeys: ViewContextKeyService; - private readonly commands: CommandRegistry; private readonly widgetManager: WidgetManager; private readonly treeViewProviders = new Map(); @@ -42,7 +41,6 @@ export class TreeViewsMainImpl implements TreeViewsMain, Disposable { this.viewRegistry = container.get(PluginViewRegistry); this.contextKeys = this.container.get(ViewContextKeyService); - this.commands = this.container.get(CommandRegistry); this.widgetManager = this.container.get(WidgetManager); } @@ -125,12 +123,6 @@ export class TreeViewsMainImpl implements TreeViewsMain, Disposable { this.contextKeys.view.set(treeViewId); this.proxy.$setSelection(treeViewId, event.map((node: TreeViewNode) => node.id)); - - // execute TreeItem.command if present - const treeNode = event[0] as TreeViewNode; - if (treeNode && treeNode.command) { - this.commands.executeCommand(treeNode.command.id, ...(treeNode.command.arguments || [])); - } })); const updateVisible = () => this.proxy.$setVisible(treeViewId, treeViewWidget.isVisible); diff --git a/packages/plugin-ext/src/plugin/tree/tree-views.ts b/packages/plugin-ext/src/plugin/tree/tree-views.ts index 500dfc4d6391c..81a79ef52b60d 100644 --- a/packages/plugin-ext/src/plugin/tree/tree-views.ts +++ b/packages/plugin-ext/src/plugin/tree/tree-views.ts @@ -226,7 +226,6 @@ class TreeViewExtImpl implements Disposable { // ask data provider for children for cached element const result = await this.treeDataProvider.getChildren(parent); - if (result) { const treeItems: TreeViewItem[] = []; const promises = result.map(async (value, index) => { @@ -234,7 +233,6 @@ class TreeViewExtImpl implements Disposable { // Ask data provider for a tree item for the value // Data provider must return theia.TreeItem const treeItem: TreeItem2 = await this.treeDataProvider.getTreeItem(value); - // Convert theia.TreeItem to the TreeViewItem // Take a label @@ -247,7 +245,7 @@ class TreeViewExtImpl implements Disposable { } // Use resource URI if label is not set - if (!label && treeItem.resourceUri) { + if (label === undefined && treeItem.resourceUri) { label = treeItem.resourceUri.path.toString(); label = decodeURIComponent(label); if (label.indexOf('/') >= 0) { @@ -260,7 +258,7 @@ class TreeViewExtImpl implements Disposable { const id = treeItem.id || `${parentId}/${index}:${label}`; // Use item ID if item label is still not set - if (!label) { + if (label === undefined) { label = treeItem.id; } @@ -314,6 +312,7 @@ class TreeViewExtImpl implements Disposable { icon, iconUrl, themeIconId, + description: treeItem.description, resourceUri: treeItem.resourceUri, tooltip: treeItem.tooltip, collapsibleState: treeItem.collapsibleState, diff --git a/packages/plugin/src/theia.d.ts b/packages/plugin/src/theia.d.ts index 03e1ad8edcc8b..01255e8a5fc8a 100644 --- a/packages/plugin/src/theia.d.ts +++ b/packages/plugin/src/theia.d.ts @@ -3877,6 +3877,12 @@ declare module '@theia/plugin' { */ iconPath?: string | Uri | { light: string | Uri; dark: string | Uri } | ThemeIcon; + /** + * A human readable string which is rendered less prominent. + * When `true`, it is derived from [resourceUri](#TreeItem.resourceUri) and when `falsy`, it is not shown. + */ + description?: string | boolean; + /** * The [uri](#Uri) of the resource representing this item. *