mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-26 01:25:38 -05:00
Bring parity with vs treeview for all non tracked code. (#23598)
This commit is contained in:
@@ -38,7 +38,7 @@ export interface ITreeItem extends vsITreeItem {
|
||||
|
||||
export interface ITreeView extends vsITreeView {
|
||||
collapse(element: ITreeItem): boolean
|
||||
readonly onDidChangeSelection: Event<ITreeItem[]>;
|
||||
readonly onDidChangeSelection: Event<readonly ITreeItem[]>;
|
||||
}
|
||||
|
||||
export type TreeViewItemHandleArg = {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
||||
import { IMenuService, MenuId, registerAction2, Action2, MenuRegistry, IMenu } from 'vs/platform/actions/common/actions';
|
||||
import { createAndFillInContextMenuActions, createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { IContextKeyService, ContextKeyExpr, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeItemLabel, IViewDescriptorService, ViewContainer, ViewContainerLocation, IViewBadge, ResolvableTreeItem, TreeCommand, ITreeViewDragAndDropController } from 'vs/workbench/common/views';
|
||||
import { TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeItemLabel, IViewDescriptorService, ViewContainer, ViewContainerLocation, IViewBadge, ResolvableTreeItem, TreeCommand, ITreeViewDragAndDropController, TreeViewPaneHandleArg } from 'vs/workbench/common/views';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||
@@ -23,12 +23,11 @@ import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels';
|
||||
import { ActionBar, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { dirname, basename } from 'vs/base/common/resources';
|
||||
import { FileThemeIcon, FolderThemeIcon, registerThemingParticipant, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { FileThemeIcon, FolderThemeIcon, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { FileKind } from 'vs/platform/files/common/files';
|
||||
import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
|
||||
import { localize } from 'vs/nls';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { textLinkForeground, textCodeBlockBackground, focusBorder, listFilterMatchHighlight, listFilterMatchHighlightBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { isString } from 'vs/base/common/types';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
@@ -60,6 +59,7 @@ import { Codicon } from 'vs/base/common/codicons';
|
||||
import { AriaRole } from 'vs/base/browser/ui/aria/aria';
|
||||
import { API_OPEN_EDITOR_COMMAND_ID, API_OPEN_DIFF_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { isCancellationError } from 'vs/base/common/errors';
|
||||
|
||||
class Root implements ITreeItem {
|
||||
label = { label: 'root' };
|
||||
@@ -119,8 +119,11 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
private readonly _onDidCollapseItem: Emitter<ITreeItem> = this._register(new Emitter<ITreeItem>());
|
||||
readonly onDidCollapseItem: Event<ITreeItem> = this._onDidCollapseItem.event;
|
||||
|
||||
private _onDidChangeSelection: Emitter<ITreeItem[]> = this._register(new Emitter<ITreeItem[]>());
|
||||
readonly onDidChangeSelection: Event<ITreeItem[]> = this._onDidChangeSelection.event;
|
||||
private _onDidChangeSelection: Emitter<readonly ITreeItem[]> = this._register(new Emitter<readonly ITreeItem[]>());
|
||||
readonly onDidChangeSelection: Event<readonly ITreeItem[]> = this._onDidChangeSelection.event;
|
||||
|
||||
private _onDidChangeFocus: Emitter<ITreeItem> = this._register(new Emitter<ITreeItem>());
|
||||
readonly onDidChangeFocus: Event<ITreeItem> = this._onDidChangeFocus.event;
|
||||
|
||||
private readonly _onDidChangeVisibility: Emitter<boolean> = this._register(new Emitter<boolean>());
|
||||
readonly onDidChangeVisibility: Event<boolean> = this._onDidChangeVisibility.event;
|
||||
@@ -140,9 +143,6 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
private readonly _onDidChangeCheckboxState: Emitter<readonly ITreeItem[]> = this._register(new Emitter<readonly ITreeItem[]>());
|
||||
readonly onDidChangeCheckboxState: Event<readonly ITreeItem[]> = this._onDidChangeCheckboxState.event;
|
||||
|
||||
private _onDidChangeFocus: Emitter<ITreeItem> = this._register(new Emitter<ITreeItem>());
|
||||
readonly onDidChangeFocus: Event<ITreeItem> = this._onDidChangeFocus.event;
|
||||
|
||||
private readonly _onDidCompleteRefresh: Emitter<void> = this._register(new Emitter<void>());
|
||||
|
||||
private nodeContext: NodeContextKey;
|
||||
@@ -180,28 +180,26 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
// Remember when adding to this method that it isn't called until the the view is visible, meaning that
|
||||
// properties could be set and events could be fired before we're initialized and that this needs to be handled.
|
||||
|
||||
this.collapseAllContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableCollapseAll`, false);
|
||||
this.collapseAllContext = this.collapseAllContextKey.bindTo(this.contextKeyService);
|
||||
this.refreshContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableRefresh`, false);
|
||||
this.refreshContext = this.refreshContextKey.bindTo(this.contextKeyService);
|
||||
|
||||
this._register(this.themeService.onDidFileIconThemeChange(() => this.doRefresh([this.root]) /** soft refresh **/));
|
||||
this._register(this.themeService.onDidColorThemeChange(() => this.doRefresh([this.root]) /** soft refresh **/));
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('explorer.decorations')) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.doRefresh([this.root]); /** soft refresh **/
|
||||
}
|
||||
}));
|
||||
this.contextKeyService.bufferChangeEvents(() => {
|
||||
this.initializeShowCollapseAllAction();
|
||||
this.initializeCollapseAllToggle();
|
||||
this.initializeShowRefreshAction();
|
||||
});
|
||||
|
||||
this.treeViewDnd = this.instantiationService.createInstance(CustomTreeViewDragAndDrop, this.id);
|
||||
if (this._dragAndDropController) {
|
||||
this.treeViewDnd.controller = this._dragAndDropController;
|
||||
}
|
||||
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('explorer.decorations')) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.doRefresh([this.root]); /** soft refresh **/
|
||||
}
|
||||
}));
|
||||
this._register(this.viewDescriptorService.onDidChangeLocation(({ views, from, to }) => {
|
||||
if (views.some(v => v.id === this.id)) {
|
||||
this.tree?.updateOptions({ overrideStyles: { listBackground: this.viewLocation === ViewContainerLocation.Sidebar ? SIDE_BAR_BACKGROUND : PANEL_BACKGROUND } });
|
||||
this.tree?.updateOptions({ overrideStyles: { listBackground: this.viewLocation === ViewContainerLocation.Panel ? PANEL_BACKGROUND : SIDE_BAR_BACKGROUND } });
|
||||
}
|
||||
}));
|
||||
this.registerActions();
|
||||
@@ -224,7 +222,6 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
get viewLocation(): ViewContainerLocation {
|
||||
return this.viewDescriptorService.getViewLocationById(this.id)!;
|
||||
}
|
||||
|
||||
private _dragAndDropController: ITreeViewDragAndDropController | undefined;
|
||||
get dragAndDropController(): ITreeViewDragAndDropController | undefined {
|
||||
return this._dragAndDropController;
|
||||
@@ -242,11 +239,8 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
}
|
||||
|
||||
set dataProvider(dataProvider: ITreeViewDataProvider | undefined) {
|
||||
if (this.tree === undefined) {
|
||||
this.createTree();
|
||||
}
|
||||
|
||||
if (dataProvider) {
|
||||
const self = this;
|
||||
this._dataProvider = new class implements ITreeViewDataProvider {
|
||||
private _isEmpty: boolean = true;
|
||||
private _onDidChangeEmpty: Emitter<void> = new Emitter();
|
||||
@@ -256,26 +250,31 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
return this._isEmpty;
|
||||
}
|
||||
|
||||
async getChildren(node: ITreeItem): Promise<ITreeItem[]> {
|
||||
let children: ITreeItem[] | undefined = undefined;
|
||||
async getChildren(node?: ITreeItem): Promise<ITreeItem[]> {
|
||||
let children: ITreeItem[];
|
||||
if (node && node.children) {
|
||||
children = node.children;
|
||||
} else {
|
||||
children = await (node instanceof Root ? dataProvider.getChildren() : dataProvider.getChildren(node));
|
||||
node.children = children;
|
||||
node = node ?? self.root;
|
||||
node.children = await (node instanceof Root ? dataProvider.getChildren() : dataProvider.getChildren(node));
|
||||
children = node.children ?? [];
|
||||
children.forEach(child => child.parent = node);
|
||||
}
|
||||
if (node instanceof Root) {
|
||||
const oldEmpty = this._isEmpty;
|
||||
this._isEmpty = !children || children.length === 0;
|
||||
this._isEmpty = children.length === 0;
|
||||
if (oldEmpty !== this._isEmpty) {
|
||||
this._onDidChangeEmpty.fire();
|
||||
}
|
||||
}
|
||||
return children ?? [];
|
||||
return children;
|
||||
}
|
||||
};
|
||||
if (this._dataProvider.onDidChangeEmpty) {
|
||||
this._register(this._dataProvider.onDidChangeEmpty(() => this._onDidChangeWelcomeState.fire()));
|
||||
this._register(this._dataProvider.onDidChangeEmpty(() => {
|
||||
this.updateCollapseAllToggle();
|
||||
this._onDidChangeWelcomeState.fire();
|
||||
}));
|
||||
}
|
||||
this.updateMessage();
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
@@ -397,6 +396,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
this.collapseAllContext?.set(showCollapseAllAction);
|
||||
}
|
||||
|
||||
|
||||
private initializeShowRefreshAction(startingValue: boolean = false) {
|
||||
if (!this.refreshContext) {
|
||||
this.refreshContextKey = new RawContextKey<boolean>(`treeView.${this.id}.enableRefresh`, startingValue, localize('treeView.enableRefresh', "Whether the tree view with id {0} enables refresh.", this.id));
|
||||
@@ -477,7 +477,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
DOM.hide(this.tree.getHTMLElement()); // make sure the tree goes out of the tabindex world by hiding it
|
||||
}
|
||||
|
||||
if (this.isVisible && this.elementsToRefresh.length) {
|
||||
if (this.isVisible && this.elementsToRefresh.length && this.dataProvider) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.doRefresh(this.elementsToRefresh);
|
||||
this.elementsToRefresh = [];
|
||||
@@ -515,15 +515,16 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
}
|
||||
|
||||
show(container: HTMLElement): void {
|
||||
this._container = container;
|
||||
DOM.append(container, this.domNode);
|
||||
}
|
||||
|
||||
private create() {
|
||||
this.domNode = DOM.$('.tree-explorer-viewlet-tree-view');
|
||||
this.messageElement = DOM.append(this.domNode, DOM.$('.message'));
|
||||
this.updateMessage();
|
||||
this.treeContainer = DOM.append(this.domNode, DOM.$('.customview-tree'));
|
||||
this.treeContainer.classList.add('file-icon-themable-tree');
|
||||
this.treeContainer.classList.add('show-file-icons');
|
||||
this.treeContainer.classList.add('file-icon-themable-tree', 'show-file-icons');
|
||||
const focusTracker = this._register(DOM.trackFocus(this.domNode));
|
||||
this._register(focusTracker.onDidFocus(() => this.focused = true));
|
||||
this._register(focusTracker.onDidBlur(() => this.focused = false));
|
||||
@@ -590,7 +591,8 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
this._onDidChangeCheckboxState.fire(items);
|
||||
}
|
||||
|
||||
private createTree() {
|
||||
|
||||
protected createTree() {
|
||||
const actionViewItemProvider = createActionViewItem.bind(undefined, this.instantiationService);
|
||||
const treeMenus = this._register(this.instantiationService.createInstance(TreeMenus, this.id));
|
||||
this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this));
|
||||
@@ -663,7 +665,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
const customTreeKey = RawCustomTreeViewContextKey.bindTo(this.tree.contextKeyService);
|
||||
customTreeKey.set(true);
|
||||
this._register(this.tree.onContextMenu(e => this.onContextMenu(treeMenus, e, actionRunner)));
|
||||
this._register(this.tree.onDidChangeSelection(e => this._onDidChangeSelection.fire(<any>e.elements)));
|
||||
this._register(this.tree.onDidChangeSelection(e => this._onDidChangeSelection.fire(e.elements)));
|
||||
this._register(this.tree.onDidChangeFocus(e => {
|
||||
if (e.elements.length) {
|
||||
this._onDidChangeFocus.fire(e.elements[0]);
|
||||
@@ -745,7 +747,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
event.stopPropagation();
|
||||
|
||||
this.tree!.setFocus([node]);
|
||||
const actions = treeMenus.getResourceContextActions(node);
|
||||
const actions = treeMenus.getResourceContextActions(node).actions;
|
||||
if (!actions.length) {
|
||||
return;
|
||||
}
|
||||
@@ -972,7 +974,7 @@ abstract class AbstractTreeView extends Disposable implements ITreeView {
|
||||
}
|
||||
|
||||
class TreeViewIdentityProvider implements IIdentityProvider<ITreeItem> {
|
||||
getId(element: ITreeItem): { toString(): string; } {
|
||||
getId(element: ITreeItem): { toString(): string } {
|
||||
return element.handle;
|
||||
}
|
||||
}
|
||||
@@ -1030,33 +1032,6 @@ class TreeDataSource implements IAsyncDataSource<ITreeItem, ITreeItem> {
|
||||
}
|
||||
}
|
||||
|
||||
// todo@joh,sandy make this proper and contributable from extensions
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
|
||||
const matchBackgroundColor = theme.getColor(listFilterMatchHighlight);
|
||||
if (matchBackgroundColor) {
|
||||
collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; background-color: ${matchBackgroundColor}; }`);
|
||||
collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; background-color: ${matchBackgroundColor}; }`);
|
||||
}
|
||||
const matchBorderColor = theme.getColor(listFilterMatchHighlightBorder);
|
||||
if (matchBorderColor) {
|
||||
collector.addRule(`.file-icon-themable-tree .monaco-list-row .content .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${matchBorderColor}; box-sizing: border-box; }`);
|
||||
collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${matchBorderColor}; box-sizing: border-box; }`);
|
||||
}
|
||||
const link = theme.getColor(textLinkForeground);
|
||||
if (link) {
|
||||
collector.addRule(`.tree-explorer-viewlet-tree-view > .message a { color: ${link}; }`);
|
||||
}
|
||||
const focusBorderColor = theme.getColor(focusBorder);
|
||||
if (focusBorderColor) {
|
||||
collector.addRule(`.tree-explorer-viewlet-tree-view > .message a:focus { outline: 1px solid ${focusBorderColor}; outline-offset: -1px; }`);
|
||||
}
|
||||
const codeBackground = theme.getColor(textCodeBlockBackground);
|
||||
if (codeBackground) {
|
||||
collector.addRule(`.tree-explorer-viewlet-tree-view > .message code { background-color: ${codeBackground}; }`);
|
||||
}
|
||||
});
|
||||
|
||||
interface ITreeExplorerTemplateData {
|
||||
readonly elementDisposable: DisposableStore;
|
||||
readonly container: HTMLElement;
|
||||
@@ -1076,7 +1051,6 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
|
||||
private _hasCheckbox: boolean = false;
|
||||
private _renderedElements = new Map<ITreeNode<ITreeItem, FuzzyScore>, ITreeExplorerTemplateData>();
|
||||
|
||||
|
||||
constructor(
|
||||
private treeViewId: string,
|
||||
private menus: TreeMenus,
|
||||
@@ -1151,7 +1125,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
|
||||
renderElement(element: ITreeNode<ITreeItem, FuzzyScore>, index: number, templateData: ITreeExplorerTemplateData): void {
|
||||
const node = element.element;
|
||||
const resource = node.resourceUri ? URI.revive(node.resourceUri) : null;
|
||||
const treeItemLabel: ITreeItemLabel | undefined = node.label ? node.label : resource ? { label: basename(resource) } : undefined;
|
||||
const treeItemLabel: ITreeItemLabel | undefined = node.label ? node.label : (resource ? { label: basename(resource) } : undefined);
|
||||
const description = isString(node.description) ? node.description : resource && node.description === true ? this.labelService.getUriLabel(dirname(resource), { relative: true }) : undefined;
|
||||
const label = treeItemLabel ? treeItemLabel.label : undefined;
|
||||
const matches = (treeItemLabel && treeItemLabel.highlights && label) ? treeItemLabel.highlights.map(([start, end]) => {
|
||||
@@ -1174,6 +1148,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
|
||||
}
|
||||
return ({ start, end });
|
||||
}) : undefined;
|
||||
// tracked change
|
||||
const isLightTheme = [ColorScheme.LIGHT, ColorScheme.HIGH_CONTRAST_LIGHT].includes(this.themeService.getColorTheme().type);
|
||||
const icon = isLightTheme ? node.icon : node.iconDark;
|
||||
const iconUrl = icon ? URI.revive(icon) : null;
|
||||
@@ -1190,23 +1165,6 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
|
||||
}
|
||||
|
||||
this.renderCheckbox(node, templateData);
|
||||
if (resource || this.isFileKindThemeIcon(node.themeIcon)) {
|
||||
const fileDecorations = this.configurationService.getValue<{ colors: boolean, badges: boolean }>('explorer.decorations');
|
||||
templateData.resourceLabel.setResource({
|
||||
name: label, description,
|
||||
resource: resource ? resource : URI.parse('missing:_icon_resource')
|
||||
},
|
||||
{
|
||||
fileKind: this.getFileKind(node),
|
||||
title,
|
||||
hideIcon: !!iconUrl,
|
||||
fileDecorations,
|
||||
extraClasses: ['custom-view-tree-node-item-resourceLabel'],
|
||||
matches: matches ? matches : createMatches(element.filterData)
|
||||
});
|
||||
} else {
|
||||
templateData.resourceLabel.setResource({ name: label, description }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches: matches ? matches : createMatches(element.filterData) });
|
||||
}
|
||||
|
||||
if (resource) {
|
||||
const fileDecorations = this.configurationService.getValue<{ colors: boolean; badges: boolean }>('explorer.decorations');
|
||||
@@ -1234,7 +1192,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
|
||||
});
|
||||
}
|
||||
|
||||
if (iconUrl || sqlIcon) {
|
||||
if (iconUrl || sqlIcon) { // tracked change
|
||||
templateData.icon.title = title ? title.toString() : '';
|
||||
templateData.icon.className = 'custom-view-tree-node-item-icon';
|
||||
if (sqlIcon) {
|
||||
@@ -1262,7 +1220,12 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
|
||||
}
|
||||
|
||||
templateData.actionBar.context = <TreeViewItemHandleArg>{ $treeViewId: this.treeViewId, $treeItemHandle: node.handle };
|
||||
templateData.actionBar.push(this.menus.getResourceActions(node), { icon: true, label: false });
|
||||
|
||||
const menuActions = this.menus.getResourceActions(node);
|
||||
if (menuActions.menus) {
|
||||
menuActions.menus.map(menu => templateData.elementDisposable.add(menu));
|
||||
}
|
||||
templateData.actionBar.push(menuActions.actions, { icon: true, label: false });
|
||||
|
||||
if (this._actionRunner) {
|
||||
templateData.actionBar.actionRunner = this._actionRunner;
|
||||
@@ -1389,7 +1352,7 @@ class Aligner extends Disposable {
|
||||
if (this._tree) {
|
||||
const parent: ITreeItem = this._tree.getParentElement(treeItem) || this._tree.getInput();
|
||||
if (this.hasIcon(parent)) {
|
||||
return false;
|
||||
return !!parent.children && parent.children.some(c => c.collapsibleState !== TreeItemCollapsibleState.None && !this.hasIcon(c));
|
||||
}
|
||||
return !!parent.children && parent.children.every(c => c.collapsibleState === TreeItemCollapsibleState.None || !this.hasIcon(c));
|
||||
} else {
|
||||
@@ -1398,8 +1361,7 @@ class Aligner extends Disposable {
|
||||
}
|
||||
|
||||
private hasIcon(node: ITreeItem): boolean {
|
||||
const isLightTheme = [ColorScheme.LIGHT, ColorScheme.HIGH_CONTRAST_LIGHT].includes(this.themeService.getColorTheme().type);
|
||||
const icon = isLightTheme ? node.icon : node.iconDark;
|
||||
const icon = this.themeService.getColorTheme().type === ColorScheme.LIGHT ? node.icon : node.iconDark;
|
||||
if (icon) {
|
||||
return true;
|
||||
}
|
||||
@@ -1420,19 +1382,19 @@ class MultipleSelectionActionRunner extends ActionRunner {
|
||||
constructor(notificationService: INotificationService, private getSelectedResources: (() => ITreeItem[])) {
|
||||
super();
|
||||
this._register(this.onDidRun(e => {
|
||||
if (e.error) {
|
||||
if (e.error && !isCancellationError(e.error)) {
|
||||
notificationService.error(localize('command-error', 'Error running command {1}: {0}. This is likely caused by the extension that contributes {1}.', e.error.message, e.action.id));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
protected override async runAction(action: IAction, context: TreeViewItemHandleArg): Promise<void> {
|
||||
protected override async runAction(action: IAction, context: TreeViewItemHandleArg | TreeViewPaneHandleArg): Promise<void> {
|
||||
const selection = this.getSelectedResources();
|
||||
let selectionHandleArgs: TreeViewItemHandleArg[] | undefined = undefined;
|
||||
let actionInSelected: boolean = false;
|
||||
if (selection.length > 1) {
|
||||
selectionHandleArgs = selection.map(selected => {
|
||||
if (selected.handle === context.$treeItemHandle) {
|
||||
if ((selected.handle === (context as TreeViewItemHandleArg).$treeItemHandle) || (context as TreeViewPaneHandleArg).$selectedTreeItems) {
|
||||
actionInSelected = true;
|
||||
}
|
||||
return { $treeViewId: context.$treeViewId, $treeItemHandle: selected.handle };
|
||||
@@ -1443,7 +1405,7 @@ class MultipleSelectionActionRunner extends ActionRunner {
|
||||
selectionHandleArgs = undefined;
|
||||
}
|
||||
|
||||
await action.run(...[context, selectionHandleArgs]);
|
||||
await action.run(context, selectionHandleArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1458,18 +1420,20 @@ class TreeMenus extends Disposable implements IDisposable {
|
||||
super();
|
||||
}
|
||||
|
||||
getResourceActions(element: ITreeItem): IAction[] {
|
||||
return this.mergeActions([ // tracked change
|
||||
this.getActions(MenuId.ViewItemContext, element, true).primary,
|
||||
this.getActions(MenuId.DataExplorerContext, element, true).primary
|
||||
]);
|
||||
getResourceActions(element: ITreeItem): { menus?: IMenu[]; actions: IAction[] } {
|
||||
const viewItemActions = this.getActions(MenuId.ViewItemContext, element, true);
|
||||
const dataExplorerActions = this.getActions(MenuId.DataExplorerContext, element, true)
|
||||
const actions = this.mergeActions([viewItemActions.primary, dataExplorerActions.primary]);
|
||||
const menus = [viewItemActions.menu, dataExplorerActions.menu];
|
||||
return { menus, actions };
|
||||
}
|
||||
|
||||
getResourceContextActions(element: ITreeItem): IAction[] {
|
||||
return this.mergeActions([ // tracked change
|
||||
this.getActions(MenuId.ViewItemContext, element).secondary,
|
||||
this.getActions(MenuId.DataExplorerContext, element).secondary
|
||||
]);
|
||||
getResourceContextActions(element: ITreeItem): { menus?: IMenu[]; actions: IAction[] } {
|
||||
const viewItemActions = this.getActions(MenuId.ViewItemContext, element);
|
||||
const dataExplorerActions = this.getActions(MenuId.DataExplorerContext, element)
|
||||
const actions = this.mergeActions([viewItemActions.secondary, dataExplorerActions.secondary]);
|
||||
const menus = [viewItemActions.menu, dataExplorerActions.menu];
|
||||
return { menus, actions };
|
||||
}
|
||||
|
||||
public setContextKeyService(service: IContextKeyService) {
|
||||
@@ -1484,6 +1448,7 @@ class TreeMenus extends Disposable implements IDisposable {
|
||||
if (!this.contextKeyService) {
|
||||
return { primary: [], secondary: [] };
|
||||
}
|
||||
|
||||
const contextKeyService = this.contextKeyService.createOverlay([
|
||||
['view', this.id],
|
||||
['viewItem', element.contextValue]
|
||||
@@ -1542,6 +1507,7 @@ export class CustomTreeView extends AbstractTreeView {
|
||||
|
||||
protected activate() {
|
||||
if (!this.activated) {
|
||||
this.createTree();
|
||||
this.progressService.withProgress({ location: this.id }, () => this.extensionService.activateByEvent(`onView:${this.id}`))
|
||||
.then(() => timeout(2000))
|
||||
.then(() => {
|
||||
|
||||
Reference in New Issue
Block a user