mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-02 09:35:40 -05:00
Adding inline actions to OE (#23101)
This commit is contained in:
@@ -46,14 +46,6 @@
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.server-explorer-viewlet .monaco-action-bar .action-label {
|
||||
margin-right: 0.3em;
|
||||
margin-left: 0.3em;
|
||||
line-height: 15px;
|
||||
width: 10px !important;
|
||||
height: 10px !important;
|
||||
}
|
||||
|
||||
/* Add space beneath the button */
|
||||
.new-connection .monaco-text-button {
|
||||
margin-bottom: 2px;
|
||||
@@ -276,3 +268,21 @@
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px 16px;
|
||||
}
|
||||
|
||||
.server-explorer-viewlet .monaco-list .monaco-list-row .actions {
|
||||
display: none;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.server-explorer-viewlet .monaco-list .monaco-list-row .actions .action-label {
|
||||
background-size: 14px 14px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.server-explorer-viewlet .monaco-list .monaco-list-row:hover .actions,
|
||||
.server-explorer-viewlet .monaco-list .monaco-list-row.selected .actions,
|
||||
.server-explorer-viewlet .monaco-list .monaco-list-row.focused .actions {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path d="M0,1H16V2.7l-6,6V15H6V8.7l-6-6ZM15,2.3V2H1v.3l6,6V14H9V8.3Zm.3,7.7.7.7-1.8,1.8L16,14.3l-.7.7-1.8-1.8L11.7,15l-.7-.7,1.8-1.8L11,10.7l.7-.7,1.8,1.8Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 253 B |
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="#fff" d="M0,1H16V2.7l-6,6V15H6V8.7l-6-6ZM15,2.3V2H1v.3l6,6V14H9V8.3Zm.3,7.7.7.7-1.8,1.8L16,14.3l-.7.7-1.8-1.8L11.7,15l-.7-.7,1.8-1.8L11,10.7l.7-.7,1.8,1.8Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 265 B |
@@ -10,7 +10,8 @@
|
||||
}
|
||||
|
||||
.monaco-workbench.vs-dark .actions-container .action-label.add-server-action,
|
||||
.monaco-workbench.hc-black .actions-container .action-label.add-server-action {
|
||||
.monaco-workbench.hc-black .actions-container .action-label.add-server-action,
|
||||
.monaco-list:focus .monaco-list-rows .actions-container .action-label.add-server-action {
|
||||
background-image: url('add_server_inverse.svg') !important;
|
||||
}
|
||||
|
||||
@@ -44,6 +45,17 @@
|
||||
background-image: url('server_page_inverse.svg') !important;
|
||||
}
|
||||
|
||||
.monaco-workbench .actions-container .action-label.remove-filter-action,
|
||||
.monaco-workbench.hc-light .actions-container .action-label.remove-filter-action {
|
||||
background-image: url('remove_filter.svg') !important;
|
||||
}
|
||||
|
||||
.monaco-workbench.vs-dark .actions-container .action-label.remove-filter-action,
|
||||
.monaco-workbench.hc-black .actions-container .action-label.remove-filter-action,
|
||||
.monaco-list:focus .monaco-list-rows .actions-container .action-label.remove-filter-action {
|
||||
background-image: url('remove_filter_inverse.svg') !important;
|
||||
}
|
||||
|
||||
/* styles for action labels - without these, the buttons for the Servers view will not be sized correctly */
|
||||
.monaco-pane-view .pane > .pane-header > .actions .action-label.icon,
|
||||
.monaco-pane-view .pane > .pane-header > .actions .action-label.codicon {
|
||||
|
||||
@@ -930,7 +930,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
|
||||
}
|
||||
}
|
||||
|
||||
private getActionContext(element: ServerTreeElement): any {
|
||||
public getActionContext(element: ServerTreeElement): any {
|
||||
let actionContext: any;
|
||||
if (element instanceof TreeNode) {
|
||||
let context = new ObjectExplorerActionsContext();
|
||||
|
||||
@@ -17,6 +17,7 @@ import { ItemContextKey } from 'sql/workbench/contrib/dashboard/browser/widgets/
|
||||
import { EditDataAction } from 'sql/workbench/browser/scriptingActions';
|
||||
import { DatabaseEngineEdition } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { ServerInfoContextKey } from 'sql/workbench/services/connection/common/serverInfoContextKey';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
|
||||
//#region -- Data Explorer
|
||||
// Script as Create
|
||||
@@ -287,6 +288,27 @@ MenuRegistry.appendMenuItem(MenuId.ObjectExplorerItemContext, {
|
||||
TreeNodeContextKey.NodeType.isEqualTo(NodeType.TableValuedFunction))
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.ObjectExplorerItemContext, {
|
||||
group: 'inline',
|
||||
order: 7,
|
||||
command: {
|
||||
id: commands.OE_REFRESH_COMMAND_ID,
|
||||
title: localize('refreshNode', "Refresh"),
|
||||
icon: Codicon.refresh
|
||||
},
|
||||
when: ContextKeyExpr.or(
|
||||
TreeNodeContextKey.NodeType.isEqualTo(NodeType.Table),
|
||||
TreeNodeContextKey.NodeType.isEqualTo(NodeType.View),
|
||||
TreeNodeContextKey.NodeType.isEqualTo(NodeType.Schema),
|
||||
TreeNodeContextKey.NodeType.isEqualTo(NodeType.User),
|
||||
TreeNodeContextKey.NodeType.isEqualTo(NodeType.UserDefinedTableType),
|
||||
TreeNodeContextKey.NodeType.isEqualTo(NodeType.StoredProcedure),
|
||||
TreeNodeContextKey.NodeType.isEqualTo(NodeType.AggregateFunction),
|
||||
TreeNodeContextKey.NodeType.isEqualTo(NodeType.PartitionFunction),
|
||||
TreeNodeContextKey.NodeType.isEqualTo(NodeType.ScalarValuedFunction),
|
||||
TreeNodeContextKey.NodeType.isEqualTo(NodeType.TableValuedFunction))
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region -- explorer widget
|
||||
|
||||
@@ -46,6 +46,7 @@ import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserve
|
||||
import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { FieldSet } from 'sql/base/browser/ui/fieldset/fieldset';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
|
||||
export interface OnShowUIResponse {
|
||||
selectedProviderDisplayName: string;
|
||||
@@ -357,34 +358,56 @@ export class ConnectionDialogWidget extends Modal {
|
||||
};
|
||||
const actionProvider = this.instantiationService.createInstance(RecentConnectionActionsProvider);
|
||||
const controller = new RecentConnectionTreeController(leftClick, actionProvider, this.connectionManagementService, this.contextMenuService);
|
||||
actionProvider.onRecentConnectionRemoved(() => {
|
||||
const recentConnections: ConnectionProfile[] = this.connectionManagementService.getRecentConnections();
|
||||
this.open(recentConnections.length > 0).catch(err => this.logService.error(`Unexpected error opening connection widget after a recent connection was removed from action provider: ${err}`));
|
||||
});
|
||||
controller.onRecentConnectionRemoved(() => {
|
||||
const recentConnections: ConnectionProfile[] = this.connectionManagementService.getRecentConnections();
|
||||
this.open(recentConnections.length > 0).catch(err => this.logService.error(`Unexpected error opening connection widget after a recent connection was removed from controller : ${err}`));
|
||||
});
|
||||
this._register(actionProvider.onRecentConnectionRemoved(async () => {
|
||||
await this.refreshTree();
|
||||
}));
|
||||
this._register(controller.onRecentConnectionRemoved(async () => {
|
||||
await this.refreshTree();
|
||||
}));
|
||||
|
||||
this._register(this.connectionManagementService.onRecentConnectionProfileDeleted(async (e) => {
|
||||
await this.refreshTree();
|
||||
}));
|
||||
|
||||
this._recentConnectionTree = TreeCreationUtils.createConnectionTree(treeContainer, this.instantiationService, this._configurationService, localize('connectionDialog.recentConnections', "Recent Connections"), controller);
|
||||
if (this._recentConnectionTree instanceof AsyncServerTree) {
|
||||
this._recentConnectionTree.onMouseClick(e => {
|
||||
this._register(this._recentConnectionTree.onMouseClick(e => {
|
||||
if (e.element instanceof ConnectionProfile) {
|
||||
this._connectionSource = 'recent';
|
||||
this.onConnectionClick(e.element, false).catch(onUnexpectedError);
|
||||
}
|
||||
});
|
||||
this._recentConnectionTree.onMouseDblClick(e => {
|
||||
}));
|
||||
|
||||
this._register(this._recentConnectionTree.onMouseDblClick(e => {
|
||||
if (e.element instanceof ConnectionProfile) {
|
||||
this._connectionSource = 'recent';
|
||||
this.onConnectionClick(e.element, true).catch(onUnexpectedError);
|
||||
}
|
||||
});
|
||||
}));
|
||||
this._register(this._recentConnectionTree.onKeyDown(e => {
|
||||
const keyboardEvent = new StandardKeyboardEvent(e);
|
||||
if (keyboardEvent.keyCode === KeyCode.Delete) {
|
||||
const element = this._recentConnectionTree.getSelection()[0];
|
||||
if (element instanceof ConnectionProfile) {
|
||||
this.connectionManagementService.clearRecentConnection(element);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// Theme styler
|
||||
this._register(styler.attachListStyler(this._recentConnectionTree, this._themeService));
|
||||
}
|
||||
|
||||
private async refreshTree() {
|
||||
try {
|
||||
const recentConnections: ConnectionProfile[] = this.connectionManagementService.getRecentConnections();
|
||||
await this.open(recentConnections.length > 0);
|
||||
} catch (err) {
|
||||
this.logService.error(`Unexpected error opening connection widget after a recent connection was removed from controller : ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
private createRecentConnections() {
|
||||
this.createRecentConnectionList();
|
||||
const noRecentConnectionContainer = DOM.append(this._noRecentConnection, DOM.$('.connection-recent-content'));
|
||||
|
||||
@@ -88,6 +88,8 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
private _onConnectionProfileGroupEdited = new Emitter<ConnectionProfileGroup>();
|
||||
private _onConnectionProfileGroupMoved = new Emitter<ConnectionElementMovedParams>();
|
||||
|
||||
private _onRecentConnectionProfileDeleted = new Emitter<ConnectionProfile>();
|
||||
|
||||
private _mementoContext: Memento;
|
||||
private _mementoObj: MementoObject;
|
||||
private _connectionStore: ConnectionStore;
|
||||
@@ -246,6 +248,10 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
return this._onConnectionProfileGroupMoved.event;
|
||||
}
|
||||
|
||||
public get onRecentConnectionProfileDeleted(): Event<ConnectionProfile> {
|
||||
return this._onRecentConnectionProfileDeleted.event;
|
||||
}
|
||||
|
||||
public get providerNameToDisplayNameMap(): { readonly [providerDisplayName: string]: string } {
|
||||
return this._providerNameToDisplayNameMap;
|
||||
}
|
||||
@@ -829,6 +835,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
|
||||
public clearRecentConnection(connectionProfile: interfaces.IConnectionProfile): void {
|
||||
this._connectionStore.removeRecentConnection(connectionProfile);
|
||||
this._onRecentConnectionProfileDeleted.fire(<ConnectionProfile>connectionProfile);
|
||||
}
|
||||
|
||||
public getActiveConnections(providers?: string[]): ConnectionProfile[] {
|
||||
|
||||
@@ -53,6 +53,7 @@ import { TestConfigurationService } from 'sql/platform/connection/test/common/te
|
||||
import { ConnectionTreeService, IConnectionTreeService } from 'sql/workbench/services/connection/common/connectionTreeService';
|
||||
import { ConnectionBrowserView } from 'sql/workbench/services/connection/browser/connectionBrowseTab';
|
||||
import { ConnectionProviderProperties, ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
suite('ConnectionDialogService tests', () => {
|
||||
const testTreeViewId = 'testTreeView';
|
||||
@@ -90,7 +91,7 @@ suite('ConnectionDialogService tests', () => {
|
||||
testInstantiationService.stub(IViewDescriptorService, viewDescriptorService);
|
||||
let errorMessageService = getMockErrorMessageService();
|
||||
let capabilitiesService = new TestCapabilitiesService();
|
||||
mockConnectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Strict,
|
||||
mockConnectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose,
|
||||
undefined, // connection dialog service
|
||||
testInstantiationService, // instantiation service
|
||||
undefined, // editor service
|
||||
@@ -129,6 +130,7 @@ suite('ConnectionDialogService tests', () => {
|
||||
}
|
||||
};
|
||||
});
|
||||
mockConnectionManagementService.setup(x => x.onRecentConnectionProfileDeleted).returns(() => new Emitter<ConnectionProfile>().event);
|
||||
testConnectionDialog = new TestConnectionDialogWidget(providerDisplayNames, providerNameToDisplayMap['MSSQL'], providerNameToDisplayMap, testInstantiationService, mockConnectionManagementService.object, undefined, undefined, viewDescriptorService, new TestThemeService(), new TestLayoutService(), new NullAdsTelemetryService(), new MockContextKeyService(), undefined, new NullLogService(), new TestTextResourcePropertiesService(new TestConfigurationService), new TestConfigurationService(), new TestCapabilitiesService());
|
||||
testConnectionDialog.render();
|
||||
testConnectionDialog['renderBody'](DOM.createStyleSheet());
|
||||
@@ -184,6 +186,7 @@ suite('ConnectionDialogService tests', () => {
|
||||
return Promise.resolve(connectionProfile);
|
||||
});
|
||||
mockConnectionManagementService.setup(x => x.isConnected(undefined, TypeMoq.It.isAny())).returns(() => true);
|
||||
|
||||
mockWidget = TypeMoq.Mock.ofType(ConnectionWidget, TypeMoq.MockBehavior.Strict, [], undefined, 'MSSQL', undefined, undefined, mockConnectionManagementService.object);
|
||||
mockWidget.setup(x => x.focusOnOpen());
|
||||
mockWidget.setup(x => x.handleOnConnecting());
|
||||
|
||||
@@ -29,6 +29,9 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { TestTreeView } from 'sql/workbench/services/connection/test/browser/testTreeView';
|
||||
import { ConnectionTreeService, IConnectionTreeService } from 'sql/workbench/services/connection/common/connectionTreeService';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||
|
||||
suite('ConnectionDialogWidget tests', () => {
|
||||
const testTreeViewId = 'testTreeView';
|
||||
const ViewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
|
||||
@@ -66,6 +69,7 @@ suite('ConnectionDialogWidget tests', () => {
|
||||
mockConnectionManagementService.setup(x => x.isConnected(undefined, TypeMoq.It.isAny())).returns(() => true);
|
||||
mockConnectionManagementService.setup(x => x.getConnectionIconId(TypeMoq.It.isAnyString())).returns(() => '');
|
||||
mockConnectionManagementService.setup(x => x.getProviderProperties(TypeMoq.It.isAnyString())).returns(() => undefined);
|
||||
mockConnectionManagementService.setup(x => x.onRecentConnectionProfileDeleted).returns(() => new Emitter<ConnectionProfile>().event);
|
||||
cmInstantiationService.stub(IConnectionManagementService, mockConnectionManagementService.object);
|
||||
let providerDisplayNames = ['Mock SQL Server'];
|
||||
let providerNameToDisplayMap = { 'MSSQL': 'Mock SQL Server' };
|
||||
|
||||
@@ -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