mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-26 17:23:15 -05:00
Adding inline actions to OE (#23101)
This commit is contained in:
@@ -24,6 +24,7 @@ import { DefaultServerGroupColor } from 'sql/workbench/services/serverGroup/comm
|
||||
import { instanceOfSqlThemeIcon } from 'sql/workbench/services/objectExplorer/common/nodeType';
|
||||
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
|
||||
import { ResourceLabel } from 'vs/workbench/browser/labels';
|
||||
import { ActionBar } from 'sql/base/browser/ui/taskbar/actionbar';
|
||||
|
||||
const DefaultConnectionIconClass = 'server-page';
|
||||
export interface ConnectionProfileGroupDisplayOptions {
|
||||
@@ -35,11 +36,13 @@ class ConnectionProfileGroupTemplate extends Disposable {
|
||||
private _icon: HTMLElement;
|
||||
private _labelContainer: HTMLElement;
|
||||
private _label: ResourceLabel;
|
||||
private _actionBar: ActionBar;
|
||||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
private _option: ConnectionProfileGroupDisplayOptions,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService
|
||||
) {
|
||||
super();
|
||||
container.parentElement!.classList.add('async-server-group');
|
||||
@@ -48,6 +51,9 @@ class ConnectionProfileGroupTemplate extends Disposable {
|
||||
this._icon = dom.append(this._root, dom.$('div.icon'));
|
||||
this._labelContainer = dom.append(this._root, dom.$('span.name'));
|
||||
this._label = this._instantiationService.createInstance(ResourceLabel, this._labelContainer, { supportHighlights: true });
|
||||
const actionsContainer = dom.append(this._label.element.element, dom.$('.actions'));
|
||||
this._actionBar = new ActionBar(actionsContainer, {
|
||||
});
|
||||
}
|
||||
|
||||
set(element: ConnectionProfileGroup, filterData: FuzzyScore) {
|
||||
@@ -63,6 +69,13 @@ class ConnectionProfileGroupTemplate extends Disposable {
|
||||
this._label.element.setLabel(element.name, '', {
|
||||
matches: createMatches(filterData)
|
||||
});
|
||||
|
||||
const actionProvider = this._objectExplorerService.getServerTreeView().treeActionProvider;
|
||||
const tree = this._objectExplorerService.getServerTreeView().tree;
|
||||
const actions = actionProvider.getActions(tree, element, true);
|
||||
this._actionBar.context = this._objectExplorerService.getServerTreeView().getActionContext(element);
|
||||
this._actionBar.clear();
|
||||
this._actionBar.pushAction(actions, { icon: true, label: false });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +104,8 @@ class ConnectionProfileTemplate extends Disposable {
|
||||
private _connectionStatusBadge: HTMLElement;
|
||||
private _labelContainer: HTMLElement;
|
||||
private _label: ResourceLabel;
|
||||
private _actionBar: ActionBar;
|
||||
|
||||
/**
|
||||
* _isCompact is used to render connections tiles with and without the action buttons.
|
||||
* When set to true, like in the connection dialog recent connections tree, the connection
|
||||
@@ -110,6 +125,9 @@ class ConnectionProfileTemplate extends Disposable {
|
||||
this._connectionStatusBadge = dom.append(this._icon, dom.$('div.connection-status-badge'));
|
||||
this._labelContainer = dom.append(this._root, dom.$('div.label'));
|
||||
this._label = this._instantiationService.createInstance(ResourceLabel, this._labelContainer, { supportHighlights: true });
|
||||
const actionsContainer = dom.append(this._label.element.element, dom.$('.actions'));
|
||||
this._actionBar = new ActionBar(actionsContainer, {
|
||||
});
|
||||
}
|
||||
|
||||
set(element: ConnectionProfile, filterData: FuzzyScore) {
|
||||
@@ -132,6 +150,19 @@ class ConnectionProfileTemplate extends Disposable {
|
||||
matches: createMatches(filterData)
|
||||
});
|
||||
this._root.title = labelText;
|
||||
const actionProvider = this._objectExplorerService.getServerTreeView().treeActionProvider;
|
||||
if (!this._isCompact) {
|
||||
const tree = this._objectExplorerService.getServerTreeView().tree;
|
||||
const actions = actionProvider.getActions(tree, element, true);
|
||||
this._actionBar.context = this._objectExplorerService.getServerTreeView().getActionContext(element);
|
||||
this._actionBar.clear();
|
||||
this._actionBar.pushAction(actions, { icon: true, label: false });
|
||||
} else {
|
||||
const actions = actionProvider.getRecentConnectionActions(element);
|
||||
this._actionBar.context = undefined;
|
||||
this._actionBar.clear();
|
||||
this._actionBar.pushAction(actions, { icon: true, label: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,16 +190,21 @@ class TreeNodeTemplate extends Disposable {
|
||||
private _icon: HTMLElement;
|
||||
private _labelContainer: HTMLElement;
|
||||
private _label: ResourceLabel;
|
||||
private _actionBar: ActionBar;
|
||||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService
|
||||
) {
|
||||
super();
|
||||
this._root = dom.append(container, dom.$('.object-element-container'));
|
||||
this._icon = dom.append(this._root, dom.$('div.object-icon'));
|
||||
this._labelContainer = dom.append(this._root, dom.$('div.label'));
|
||||
this._label = this._instantiationService.createInstance(ResourceLabel, this._labelContainer, { supportHighlights: true });
|
||||
const actionsContainer = dom.append(this._label.element.element, dom.$('.actions'));
|
||||
this._actionBar = new ActionBar(actionsContainer, {
|
||||
});
|
||||
}
|
||||
|
||||
set(element: TreeNode, filterData: FuzzyScore) {
|
||||
@@ -211,6 +247,12 @@ class TreeNodeTemplate extends Disposable {
|
||||
matches: createMatches(filterData)
|
||||
});
|
||||
this._root.title = labelText;
|
||||
const tree = this._objectExplorerService.getServerTreeView().tree;
|
||||
const actionProvider = this._objectExplorerService.getServerTreeView().treeActionProvider;
|
||||
const actions = actionProvider.getActions(tree, element, true);
|
||||
this._actionBar.context = this._objectExplorerService.getServerTreeView().getActionContext(element);
|
||||
this._actionBar.clear();
|
||||
this._actionBar.pushAction(actions, { icon: true, label: false });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
|
||||
import { SqlIconId } from 'sql/base/common/codicons';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
|
||||
@@ -44,7 +45,7 @@ export class RefreshAction extends Action {
|
||||
@IErrorMessageService private _errorMessageService: IErrorMessageService,
|
||||
@ILogService private _logService: ILogService
|
||||
) {
|
||||
super(id, label);
|
||||
super(id, label, Codicon.refresh.classNames);
|
||||
}
|
||||
public override async run(): Promise<void> {
|
||||
let treeNode: TreeNode | undefined = undefined;
|
||||
@@ -103,8 +104,7 @@ export class EditConnectionAction extends Action {
|
||||
private _connectionProfile: ConnectionProfile,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
|
||||
) {
|
||||
super(id, label);
|
||||
this.class = 'edit-server-action';
|
||||
super(id, label, Codicon.edit.classNames);
|
||||
}
|
||||
|
||||
public override async run(): Promise<void> {
|
||||
@@ -124,7 +124,7 @@ export class DisconnectConnectionAction extends Action {
|
||||
private _connectionProfile: ConnectionProfile,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
|
||||
) {
|
||||
super(id, label);
|
||||
super(id, label, Codicon.debugDisconnect.classNames);
|
||||
}
|
||||
|
||||
override async run(actionContext: ObjectExplorerActionsContext): Promise<any> {
|
||||
@@ -223,8 +223,7 @@ export class EditServerGroupAction extends Action {
|
||||
private _group: ConnectionProfileGroup,
|
||||
@IServerGroupController private readonly serverGroupController: IServerGroupController
|
||||
) {
|
||||
super(id, label);
|
||||
this.class = 'edit-server-group-action';
|
||||
super(id, label, Codicon.edit.classNames);
|
||||
}
|
||||
|
||||
public override run(): Promise<void> {
|
||||
@@ -277,8 +276,7 @@ export class DeleteConnectionAction extends Action {
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@IDialogService private _dialogService: IDialogService
|
||||
) {
|
||||
super(id, label);
|
||||
this.class = 'delete-connection-action';
|
||||
super(id, label, Codicon.trash.classNames);
|
||||
if (element instanceof ConnectionProfileGroup && element.id === UNSAVED_GROUP_ID) {
|
||||
this.enabled = false;
|
||||
}
|
||||
@@ -322,14 +320,19 @@ export class FilterChildrenAction extends Action {
|
||||
label: string,
|
||||
private _node: TreeNode,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService) {
|
||||
super(id, label);
|
||||
super(id, label, getFilterActionIconClass(_node));
|
||||
}
|
||||
|
||||
public override async run(): Promise<void> {
|
||||
await this._objectExplorerService.getServerTreeView().filterElementChildren(this._node);
|
||||
this.class = getFilterActionIconClass(this._node);
|
||||
}
|
||||
}
|
||||
|
||||
function getFilterActionIconClass(node: TreeNode): string {
|
||||
return node.filters.length > 0 ? Codicon.filterFilled.classNames : Codicon.filter.classNames;
|
||||
}
|
||||
|
||||
export class RemoveFilterAction extends Action {
|
||||
public static ID = 'objectExplorer.removeFilter';
|
||||
public static LABEL = localize('objectExplorer.removeFilter', "Remove Filter");
|
||||
@@ -343,7 +346,7 @@ export class RemoveFilterAction extends Action {
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
|
||||
@IAdsTelemetryService private _telemetryService: IAdsTelemetryService
|
||||
) {
|
||||
super(id, label);
|
||||
super(id, label, SqlIconId.removeFilter);
|
||||
}
|
||||
|
||||
public override async run(): Promise<void> {
|
||||
@@ -373,3 +376,23 @@ export class RemoveFilterAction extends Action {
|
||||
}).send();
|
||||
}
|
||||
}
|
||||
|
||||
export class DeleteRecentConnectionsAction extends Action {
|
||||
public static ID = 'registeredServers.clearRecentConnections';
|
||||
public static LABEL = localize('registeredServers.clearRecentConnections', "Delete");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
private _connectionProfile: ConnectionProfile,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
|
||||
) {
|
||||
super(id, label, Codicon.trash.classNames);
|
||||
}
|
||||
|
||||
public override async run(): Promise<void> {
|
||||
if (this._connectionProfile) {
|
||||
this._connectionManagementService.clearRecentConnection(this._connectionProfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ export interface IServerTreeView {
|
||||
layout(size: number): void;
|
||||
showFilteredTree(view: ServerTreeViewView): void;
|
||||
filterElementChildren(node: TreeNode): Promise<void>;
|
||||
getActionContext(element: ServerTreeElement): any;
|
||||
view: ServerTreeViewView;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
import {
|
||||
DisconnectConnectionAction, EditConnectionAction,
|
||||
DeleteConnectionAction, RefreshAction, EditServerGroupAction, AddServerAction, FilterChildrenAction, RemoveFilterAction
|
||||
DeleteConnectionAction, RefreshAction, EditServerGroupAction, AddServerAction, FilterChildrenAction, RemoveFilterAction, DeleteRecentConnectionsAction
|
||||
} from 'sql/workbench/services/objectExplorer/browser/connectionTreeAction';
|
||||
import { TreeNode } from 'sql/workbench/services/objectExplorer/common/treeNode';
|
||||
import { NodeType } from 'sql/workbench/services/objectExplorer/common/nodeType';
|
||||
@@ -52,9 +52,9 @@ export class ServerTreeActionProvider {
|
||||
/**
|
||||
* Return actions given an element in the tree
|
||||
*/
|
||||
public getActions(tree: AsyncServerTree | ITree, element: ServerTreeElement): IAction[] {
|
||||
public getActions(tree: AsyncServerTree | ITree, element: ServerTreeElement, inlineOnly: boolean = false): IAction[] {
|
||||
if (element instanceof ConnectionProfile) {
|
||||
return this.getConnectionActions(tree, element);
|
||||
return this.getConnectionActions(tree, element, inlineOnly);
|
||||
}
|
||||
if (element instanceof ConnectionProfileGroup) {
|
||||
return this.getConnectionProfileGroupActions(element);
|
||||
@@ -66,7 +66,7 @@ export class ServerTreeActionProvider {
|
||||
tree: tree,
|
||||
profile,
|
||||
treeNode: element
|
||||
});
|
||||
}, inlineOnly);
|
||||
}
|
||||
}
|
||||
return [];
|
||||
@@ -95,10 +95,18 @@ export class ServerTreeActionProvider {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
public getRecentConnectionActions(element: ConnectionProfile): IAction[] {
|
||||
return [
|
||||
this._instantiationService.createInstance(EditConnectionAction, EditConnectionAction.ID, EditConnectionAction.LABEL, element),
|
||||
this._instantiationService.createInstance(DeleteRecentConnectionsAction, DeleteRecentConnectionsAction.ID, DeleteRecentConnectionsAction.LABEL, element)
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Return actions for connection elements
|
||||
*/
|
||||
private getConnectionActions(tree: AsyncServerTree | ITree, profile: ConnectionProfile): IAction[] {
|
||||
private getConnectionActions(tree: AsyncServerTree | ITree, profile: ConnectionProfile, inlineOnly: boolean = false): IAction[] {
|
||||
let node = new TreeNode(NodeType.Server, NodeType.Server, '', false, '', '', '', '', undefined, undefined, undefined, undefined);
|
||||
// Only update password and not access tokens to avoid login prompts when opening context menu.
|
||||
this._connectionManagementService.addSavedPassword(profile, true);
|
||||
@@ -107,10 +115,11 @@ export class ServerTreeActionProvider {
|
||||
tree: tree,
|
||||
profile: profile,
|
||||
treeNode: node
|
||||
}, (context) => this.getBuiltinConnectionActions(context));
|
||||
}, (context) => this.getBuiltinConnectionActions(context),
|
||||
inlineOnly);
|
||||
}
|
||||
|
||||
private getAllActions(context: ObjectExplorerContext, getDefaultActions: (context: ObjectExplorerContext) => IAction[]) {
|
||||
private getAllActions(context: ObjectExplorerContext, getDefaultActions: (context: ObjectExplorerContext) => IAction[], inlineOnly: boolean = false) {
|
||||
// Create metadata needed to get a useful set of actions
|
||||
let scopedContextService = this.getContextKeyService(context);
|
||||
let menu = this.menuService.createMenu(MenuId.ObjectExplorerItemContext, scopedContextService);
|
||||
@@ -118,8 +127,11 @@ export class ServerTreeActionProvider {
|
||||
// Fill in all actions
|
||||
const builtIn = getDefaultActions(context);
|
||||
const actions: IAction[] = [];
|
||||
const options = { arg: undefined, shouldForwardArgs: true };
|
||||
const groups = menu.getActions(options);
|
||||
const options = {
|
||||
arg: undefined, shouldForwardArgs: true
|
||||
};
|
||||
|
||||
let groups = menu.getActions(options);
|
||||
let insertIndex: number | undefined = 0;
|
||||
const queryIndex = groups.findIndex(v => {
|
||||
if (v[0] === '0_query') {
|
||||
@@ -132,24 +144,36 @@ export class ServerTreeActionProvider {
|
||||
}
|
||||
});
|
||||
insertIndex = queryIndex > -1 ? insertIndex + groups[queryIndex][1].length : undefined;
|
||||
fillInActions(groups, actions, false);
|
||||
|
||||
if (insertIndex) {
|
||||
if (!(actions[insertIndex] instanceof Separator) && builtIn.length > 0) {
|
||||
builtIn.unshift(new Separator());
|
||||
}
|
||||
actions?.splice(insertIndex, 0, ...builtIn);
|
||||
} else {
|
||||
if (actions.length > 0 && builtIn.length > 0) {
|
||||
builtIn.push(new Separator());
|
||||
}
|
||||
if (inlineOnly) {
|
||||
groups = groups.filter(g => g[0].includes('inline'));
|
||||
fillInActions(groups, actions, false);
|
||||
actions.unshift(...builtIn);
|
||||
// Moving refresh action to the end of the list
|
||||
const refreshIndex = actions.findIndex(f => {
|
||||
return f instanceof RefreshAction;
|
||||
});
|
||||
if (refreshIndex > -1) {
|
||||
actions.push(actions.splice(refreshIndex, 1)[0]);
|
||||
}
|
||||
} else {
|
||||
fillInActions(groups, actions, false);
|
||||
if (insertIndex) {
|
||||
if (!(actions[insertIndex] instanceof Separator) && builtIn.length > 0 && !inlineOnly) {
|
||||
builtIn.unshift(new Separator());
|
||||
}
|
||||
actions?.splice(insertIndex, 0, ...builtIn);
|
||||
} else {
|
||||
if (actions.length > 0 && builtIn.length > 0) {
|
||||
builtIn.push(new Separator());
|
||||
}
|
||||
actions.unshift(...builtIn);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
menu.dispose();
|
||||
return actions;
|
||||
|
||||
}
|
||||
|
||||
private getBuiltinConnectionActions(context: ObjectExplorerContext): IAction[] {
|
||||
@@ -209,8 +233,8 @@ export class ServerTreeActionProvider {
|
||||
/**
|
||||
* Return actions for OE elements
|
||||
*/
|
||||
private getObjectExplorerNodeActions(context: ObjectExplorerContext): IAction[] {
|
||||
return this.getAllActions(context, (context) => this.getBuiltInNodeActions(context));
|
||||
private getObjectExplorerNodeActions(context: ObjectExplorerContext, inlineOnly: boolean = false): IAction[] {
|
||||
return this.getAllActions(context, (context) => this.getBuiltInNodeActions(context), inlineOnly);
|
||||
}
|
||||
|
||||
private getBuiltInNodeActions(context: ObjectExplorerContext): IAction[] {
|
||||
@@ -226,16 +250,15 @@ export class ServerTreeActionProvider {
|
||||
}
|
||||
// Contribute refresh action for scriptable objects via contribution
|
||||
if (!this.isScriptableObject(context)) {
|
||||
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, context.tree, context.treeNode || context.profile));
|
||||
|
||||
// Adding filter action if the node has filter properties
|
||||
if (treeNode?.filterProperties?.length > 0 && this._configurationService.getValue<boolean>(CONFIG_WORKBENCH_ENABLEPREVIEWFEATURES)) {
|
||||
actions.push(this._instantiationService.createInstance(FilterChildrenAction, FilterChildrenAction.ID, FilterChildrenAction.LABEL, context.treeNode));
|
||||
}
|
||||
// Adding remove filter action if the node has filters applied to it.
|
||||
// Adding remove filter action if the node has filters applied to it and the action is not inline only.
|
||||
if (treeNode?.filters?.length > 0) {
|
||||
actions.push(this._instantiationService.createInstance(RemoveFilterAction, RemoveFilterAction.ID, RemoveFilterAction.LABEL, context.treeNode, context.tree, undefined));
|
||||
}
|
||||
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, context.tree, context.treeNode || context.profile));
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user