Skip to content

Commit 81b98d6

Browse files
authored
Toolbars: ToolbarItem.when field is evaluated and respected (#12067)
ToolbarItem when field is now respected by toolbar and tab-bar-toolbar + when clause can be set in toolbar.json Signed-off-by: Jonah Iden <[email protected]>
1 parent 2266025 commit 81b98d6

File tree

3 files changed

+53
-8
lines changed

3 files changed

+53
-8
lines changed

packages/core/src/browser/shell/tab-bar-toolbar/tab-bar-toolbar.tsx

+39-6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import { inject, injectable } from 'inversify';
1818
import * as React from 'react';
19+
import { ContextKeyService } from '../../context-key-service';
1920
import { CommandRegistry, Disposable, DisposableCollection, MenuCommandExecutor, MenuModelRegistry, MenuPath, nls } from '../../../common';
2021
import { Anchor, ContextMenuAccess, ContextMenuRenderer } from '../../context-menu-renderer';
2122
import { LabelIcon, LabelParser } from '../../label-parser';
@@ -41,12 +42,15 @@ export class TabBarToolbar extends ReactWidget {
4142
protected inline = new Map<string, TabBarToolbarItem | ReactTabBarToolbarItem>();
4243
protected more = new Map<string, TabBarToolbarItem>();
4344

45+
protected contextKeyListener: Disposable | undefined;
46+
4447
@inject(CommandRegistry) protected readonly commands: CommandRegistry;
4548
@inject(LabelParser) protected readonly labelParser: LabelParser;
4649
@inject(MenuModelRegistry) protected readonly menus: MenuModelRegistry;
4750
@inject(MenuCommandExecutor) protected readonly menuCommandExecutor: MenuCommandExecutor;
4851
@inject(ContextMenuRenderer) protected readonly contextMenuRenderer: ContextMenuRenderer;
4952
@inject(TabBarToolbarRegistry) protected readonly toolbarRegistry: TabBarToolbarRegistry;
53+
@inject(ContextKeyService) protected readonly contextKeyService: ContextKeyService;
5054

5155
constructor() {
5256
super();
@@ -60,13 +64,22 @@ export class TabBarToolbar extends ReactWidget {
6064
updateItems(items: Array<TabBarToolbarItem | ReactTabBarToolbarItem>, current: Widget | undefined): void {
6165
this.inline.clear();
6266
this.more.clear();
67+
68+
const contextKeys = new Set<string>();
6369
for (const item of items.sort(TabBarToolbarItem.PRIORITY_COMPARATOR).reverse()) {
6470
if ('render' in item || item.group === undefined || item.group === 'navigation') {
6571
this.inline.set(item.id, item);
6672
} else {
6773
this.more.set(item.id, item);
6874
}
75+
76+
if (item.when) {
77+
this.contextKeyService.parseKeys(item.when)?.forEach(key => contextKeys.add(key));
78+
}
6979
}
80+
81+
this.updateContextKeyListener(contextKeys);
82+
7083
this.setCurrent(current);
7184
if (!items.length) {
7285
this.hide();
@@ -97,6 +110,17 @@ export class TabBarToolbar extends ReactWidget {
97110
}
98111
}
99112

113+
protected updateContextKeyListener(contextKeys: Set<string>): void {
114+
this.contextKeyListener?.dispose();
115+
if (contextKeys.size > 0) {
116+
this.contextKeyListener = this.contextKeyService.onDidChange(event => {
117+
if (event.affects(contextKeys)) {
118+
this.update();
119+
}
120+
});
121+
}
122+
}
123+
100124
protected render(): React.ReactNode {
101125
return <React.Fragment>
102126
{this.renderMore()}
@@ -124,7 +148,8 @@ export class TabBarToolbar extends ReactWidget {
124148
classNames.push(iconClass);
125149
}
126150
const tooltip = item.tooltip || (command && command.label);
127-
const toolbarItemClassNames = this.getToolbarItemClassNames(command?.id ?? item.command);
151+
152+
const toolbarItemClassNames = this.getToolbarItemClassNames(item);
128153
if (item.menuPath && !item.command) { toolbarItemClassNames.push('enabled'); }
129154
return <div key={item.id}
130155
ref={this.onRender}
@@ -139,13 +164,13 @@ export class TabBarToolbar extends ReactWidget {
139164
</div>;
140165
}
141166

142-
protected getToolbarItemClassNames(commandId: string | undefined): string[] {
167+
protected getToolbarItemClassNames(item: AnyToolbarItem): string[] {
143168
const classNames = [TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM];
144-
if (commandId) {
145-
if (this.commandIsEnabled(commandId)) {
169+
if (item.command) {
170+
if (this.commandIsEnabled(item.command) && this.evaluateWhenClause(item.when)) {
146171
classNames.push('enabled');
147172
}
148-
if (this.commandIsToggled(commandId)) {
173+
if (this.commandIsToggled(item.command)) {
149174
classNames.push('toggled');
150175
}
151176
}
@@ -221,11 +246,20 @@ export class TabBarToolbar extends ReactWidget {
221246
return this.commands.isToggled(command, this.current);
222247
}
223248

249+
protected evaluateWhenClause(whenClause: string | undefined): boolean {
250+
return whenClause ? this.contextKeyService.match(whenClause) : true;
251+
}
252+
224253
protected executeCommand = (e: React.MouseEvent<HTMLElement>) => {
225254
e.preventDefault();
226255
e.stopPropagation();
227256

228257
const item: AnyToolbarItem | undefined = this.inline.get(e.currentTarget.id);
258+
259+
if (!this.evaluateWhenClause(item?.when)) {
260+
return;
261+
}
262+
229263
if (item?.command && item.menuPath) {
230264
this.menuCommandExecutor.executeCommand(item.menuPath, item.command, this.current);
231265
} else if (item?.command) {
@@ -245,7 +279,6 @@ export class TabBarToolbar extends ReactWidget {
245279
protected onMouseUpEvent = (e: React.MouseEvent<HTMLElement>) => {
246280
e.currentTarget.classList.remove('active');
247281
};
248-
249282
}
250283

251284
export namespace TabBarToolbar {

packages/toolbar/src/browser/toolbar-preference-schema.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ const toolbarColumnGroup: IJSONSchema = {
3131
'command': { 'type': 'string' },
3232
'icon': { 'type': 'string' },
3333
'tooltip': { 'type': 'string' },
34-
'group': { 'enum': ['contributed'] }
34+
'group': { 'enum': ['contributed'] },
35+
'when': { 'type': 'string' },
3536
},
3637
'required': [
3738
'id',

packages/toolbar/src/browser/toolbar.tsx

+12-1
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,20 @@ export class ToolbarImpl extends TabBarToolbar {
7777
protected updateInlineItems(): void {
7878
this.inline.clear();
7979
const { items } = this.model.toolbarItems;
80+
81+
const contextKeys = new Set<string>();
8082
for (const column of Object.keys(items)) {
8183
for (const group of items[column as ToolbarAlignment]) {
8284
for (const item of group) {
8385
this.inline.set(item.id, item);
86+
87+
if (item.when) {
88+
this.contextKeyService.parseKeys(item.when)?.forEach(key => contextKeys.add(key));
89+
}
8490
}
8591
}
8692
}
93+
this.updateContextKeyListener(contextKeys);
8794
}
8895

8996
protected handleContextMenu = (e: React.MouseEvent<HTMLDivElement>): ContextMenuAccess => this.doHandleContextMenu(e);
@@ -225,8 +232,12 @@ export class ToolbarImpl extends TabBarToolbar {
225232
const stringifiedPosition = JSON.stringify(position);
226233
let toolbarItemClassNames = '';
227234
let renderBody: React.ReactNode;
235+
228236
if (TabBarToolbarItem.is(item)) {
229-
toolbarItemClassNames = [TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM, 'enabled'].join(' ');
237+
toolbarItemClassNames = TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM;
238+
if (this.evaluateWhenClause(item.when)) {
239+
toolbarItemClassNames += ' enabled';
240+
}
230241
renderBody = this.renderItem(item);
231242
} else {
232243
const contribution = this.model.getContributionByID(item.id);

0 commit comments

Comments
 (0)