Update server tree action contributions (#15525)

* Update server tree action contributions

* Fix test
This commit is contained in:
Charles Gagnon
2021-05-20 12:41:56 -07:00
committed by GitHub
parent c61c53976a
commit 2ec720d5b9
19 changed files with 176 additions and 213 deletions

View File

@@ -5,11 +5,10 @@
import { IConfigurationRegistry, Extensions as ConfigExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { AddServerGroupAction, AddServerAction } from 'sql/workbench/services/objectExplorer/browser/connectionTreeAction';
import { ClearRecentConnectionsAction, GetCurrentConnectionStringAction } from 'sql/workbench/services/connection/browser/connectionActions';
import * as azdata from 'azdata';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { localize } from 'vs/nls';
import { ConnectionStatusbarItem } from 'sql/workbench/contrib/connection/browser/connectionStatus';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
@@ -20,12 +19,18 @@ import { integrated, azureMFA } from 'sql/platform/connection/common/constants';
import { AuthenticationType } from 'sql/workbench/services/connection/browser/connectionWidget';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { ConnectionViewletPanel } from 'sql/workbench/contrib/dataExplorer/browser/connectionViewletPanel';
import { ContextKeyEqualsExpr } from 'vs/platform/contextkey/common/contextkey';
import { ActiveConnectionsFilterAction, AddServerAction, AddServerGroupAction } from 'sql/workbench/services/objectExplorer/browser/connectionTreeAction';
import { CONTEXT_SERVER_TREE_VIEW, CONTEXT_SERVER_TREE_HAS_CONNECTIONS } from 'sql/workbench/contrib/objectExplorer/browser/serverTreeView';
import { SqlIconId } from 'sql/base/common/codicons';
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(ConnectionStatusbarItem, LifecyclePhase.Restored);
import 'sql/workbench/contrib/connection/common/connectionTreeProviderExentionPoint';
import { ServerTreeViewView } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
// Connection Dashboard registration
@@ -50,6 +55,15 @@ actionRegistry.registerWorkbenchAction(
AddServerGroupAction.LABEL
);
actionRegistry.registerWorkbenchAction(
SyncActionDescriptor.create(
ActiveConnectionsFilterAction,
ActiveConnectionsFilterAction.ID,
ActiveConnectionsFilterAction.SHOW_ACTIVE_CONNECTIONS_LABEL
),
ActiveConnectionsFilterAction.SHOW_ACTIVE_CONNECTIONS_LABEL
);
actionRegistry.registerWorkbenchAction(
SyncActionDescriptor.create(
AddServerAction,
@@ -59,6 +73,45 @@ actionRegistry.registerWorkbenchAction(
AddServerAction.LABEL
);
MenuRegistry.appendMenuItem(MenuId.ViewTitle, {
group: 'navigation',
order: 10,
command: {
id: AddServerAction.ID,
title: AddServerAction.LABEL,
icon: { id: SqlIconId.addServerAction }
},
when: ContextKeyEqualsExpr.create('view', ConnectionViewletPanel.ID),
});
MenuRegistry.appendMenuItem(MenuId.ViewTitle, {
group: 'navigation',
order: 20,
command: {
id: AddServerGroupAction.ID,
title: AddServerGroupAction.LABEL,
icon: { id: SqlIconId.addServerGroupAction }
},
when: ContextKeyEqualsExpr.create('view', ConnectionViewletPanel.ID),
});
MenuRegistry.appendMenuItem(MenuId.ViewTitle, {
group: 'navigation',
order: 30,
command: {
id: ActiveConnectionsFilterAction.ID,
title: ActiveConnectionsFilterAction.SHOW_ACTIVE_CONNECTIONS_LABEL,
icon: { id: SqlIconId.activeConnectionsAction },
precondition: CONTEXT_SERVER_TREE_HAS_CONNECTIONS,
toggled: {
condition: CONTEXT_SERVER_TREE_VIEW.isEqualTo(ServerTreeViewView.active),
icon: { id: SqlIconId.serverPage },
tooltip: ActiveConnectionsFilterAction.SHOW_ALL_CONNECTIONS_LABEL
}
},
when: ContextKeyEqualsExpr.create('view', ConnectionViewletPanel.ID),
});
CommandsRegistry.registerCommand('azdata.connect',
function (accessor, args: {
serverName: string,

View File

@@ -10,12 +10,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IAction } from 'vs/base/common/actions';
import { ServerTreeView } from 'sql/workbench/contrib/objectExplorer/browser/serverTreeView';
import {
ActiveConnectionsFilterAction,
AddServerAction, AddServerGroupAction
} from 'sql/workbench/services/objectExplorer/browser/connectionTreeAction';
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane';
@@ -33,9 +28,6 @@ export class ConnectionViewletPanel extends ViewPane {
private _root?: HTMLElement;
private _serverTreeView: ServerTreeView;
private _addServerAction: IAction;
private _addServerGroupAction: IAction;
private _activeConnectionsFilterAction: ActiveConnectionsFilterAction;
constructor(
private options: IViewletViewOptions,
@@ -52,18 +44,11 @@ export class ConnectionViewletPanel extends ViewPane {
@ITelemetryService telemetryService: ITelemetryService,
) {
super({ ...(options as IViewPaneOptions) }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, opener, themeService, telemetryService);
this._addServerAction = this.instantiationService.createInstance(AddServerAction,
AddServerAction.ID,
AddServerAction.LABEL);
this._addServerGroupAction = this.instantiationService.createInstance(AddServerGroupAction,
AddServerGroupAction.ID,
AddServerGroupAction.LABEL);
this._serverTreeView = <any>this.objectExplorerService.getServerTreeView() as ServerTreeView;
this._serverTreeView = this.objectExplorerService.getServerTreeView() as ServerTreeView;
if (!this._serverTreeView) {
this._serverTreeView = this.instantiationService.createInstance(ServerTreeView);
this.objectExplorerService.registerServerTreeView(this._serverTreeView);
}
this._activeConnectionsFilterAction = this._serverTreeView.activeConnectionsFilterAction;
}
protected renderHeader(container: HTMLElement): void {
@@ -114,14 +99,6 @@ export class ConnectionViewletPanel extends ViewPane {
return 0;
}
public getActions(): IAction[] {
return [
this._addServerAction,
this._addServerGroupAction,
this._activeConnectionsFilterAction
];
}
public clearSearch() {
this._serverTreeView.refreshTree();
}

View File

@@ -27,6 +27,7 @@ import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneCont
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { Viewlet } from 'vs/workbench/browser/viewlet';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { SqlIconId } from 'sql/base/common/codicons';
export const VIEWLET_ID = 'workbench.view.connections';
@@ -132,8 +133,6 @@ export class DataExplorerViewPaneContainer extends ViewPaneContainer {
}
}
export const dataExplorerIconId = 'dataExplorer';
export const VIEW_CONTAINER = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({
id: VIEWLET_ID,
title: localize('dataexplorer.name', "Connections"),
@@ -144,7 +143,7 @@ export const VIEW_CONTAINER = Registry.as<IViewContainersRegistry>(ViewContainer
keybindings: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_D },
order: 0
},
icon: { id: 'dataExplorer' },
icon: { id: SqlIconId.dataExplorer },
order: 0,
storageId: `${VIEWLET_ID}.state`
}, ViewContainerLocation.Sidebar, { isDefault: true });

View File

@@ -4,29 +4,38 @@
*--------------------------------------------------------------------------------------------*/
/* Icons for various registered servers actions */
.monaco-workbench .add-server-action {
background-image: url('add_server.svg');
.monaco-workbench .dataExplorer-viewlet .actions-container .action-label.add-server-action {
background-image: url('add_server.svg') !important;
}
.monaco-workbench.vs-dark .add-server-action,
.monaco-workbench.hc-black .add-server-action {
background-image: url('add_server_inverse.svg');
.monaco-workbench.vs-dark .dataExplorer-viewlet .actions-container .action-label.add-server-action,
.monaco-workbench.hc-black .dataExplorer-viewlet .actions-container .action-label.add-server-action {
background-image: url('add_server_inverse.svg') !important;
}
.monaco-workbench .add-server-group-action {
background-image: url('new_servergroup.svg');
.monaco-workbench .dataExplorer-viewlet .actions-container .action-label.add-server-group-action {
background-image: url('new_servergroup.svg') !important;
}
.monaco-workbench.vs-dark .add-server-group-action,
.monaco-workbench.hc-black .add-server-group-action {
background-image: url('new_servergroup_inverse.svg');
.monaco-workbench.vs-dark .dataExplorer-viewlet .actions-container .action-label.add-server-group-action,
.monaco-workbench.hc-black .dataExplorer-viewlet .actions-container .action-label.add-server-group-action {
background-image: url('new_servergroup_inverse.svg') !important;
}
.monaco-workbench .active-connections-action {
background-image: url('connected_active_server.svg');
.monaco-workbench .dataExplorer-viewlet .actions-container .action-label.active-connections-action {
background-image: url('connected_active_server.svg') !important;
}
.monaco-workbench.vs-dark .active-connections-action,
.monaco-workbench.hc-black .active-connections-action{
background-image: url('connected_active_server_inverse.svg');
.monaco-workbench.vs-dark .dataExplorer-viewlet .actions-container .action-label.active-connections-action,
.monaco-workbench.hc-black .dataExplorer-viewlet .actions-container .action-label.active-connections-action {
background-image: url('connected_active_server_inverse.svg') !important;
}
.monaco-workbench .dataExplorer-viewlet .actions-container .action-label.server-page {
background-image: url('server_page.svg') !important;
}
.monaco-workbench.vs-dark .dataExplorer-viewlet .actions-container .action-label.server-page,
.monaco-workbench.hc-black .dataExplorer-viewlet .actions-container .action-label.server-page {
background-image: url('server_page_inverse.svg') !important;
}

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#212121;}.cls-2{fill:#231f20;}</style></defs><title>server_16x16</title><path class="cls-1" d="M0,0V16H10.53V0ZM1,1H9.53v9H1ZM9.53,15H1V11H9.53Z"/><path class="cls-2" d="M4.39,4.23H1.94V1.77H4.39Zm-2-.5H3.89V2.27H2.44Z"/></svg>

After

Width:  |  Height:  |  Size: 345 B

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>server_inverse_16x16</title><path class="cls-1" d="M2.73,0V16H13.26V0Zm1,1h8.53v9H3.73ZM12.26,15H3.73V11h8.53Z"/><path class="cls-1" d="M7.21,4.23H4.75V1.77H7.21Zm-2-.5H6.71V2.27H5.25Z"/></svg>

After

Width:  |  Height:  |  Size: 339 B

View File

@@ -19,12 +19,11 @@ import { append, $, hide, show } from 'vs/base/browser/dom';
import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
import * as ConnectionUtils from 'sql/platform/connection/common/utils';
import { ActiveConnectionsFilterAction } from 'sql/workbench/services/objectExplorer/browser/connectionTreeAction';
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
import { TreeCreationUtils } from 'sql/workbench/services/objectExplorer/browser/treeCreationUtils';
import { TreeUpdateUtils } from 'sql/workbench/services/objectExplorer/browser/treeUpdateUtils';
import { TreeSelectionHandler } from 'sql/workbench/services/objectExplorer/browser/treeSelectionHandler';
import { IObjectExplorerService, IServerTreeView } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
import { IObjectExplorerService, IServerTreeView, ServerTreeViewView } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { Button } from 'sql/base/browser/ui/button/button';
import { TreeNode, TreeItemCollapsibleState } from 'sql/workbench/services/objectExplorer/common/treeNode';
@@ -42,6 +41,10 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
import { coalesce } from 'vs/base/common/arrays';
import { CONNECTIONS_SORT_BY_CONFIG_KEY } from 'sql/platform/connection/common/connectionConfig';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
export const CONTEXT_SERVER_TREE_VIEW = new RawContextKey<ServerTreeViewView>('serverTreeView.view', ServerTreeViewView.all);
export const CONTEXT_SERVER_TREE_HAS_CONNECTIONS = new RawContextKey<boolean>('serverTreeView.hasConnections', false);
/**
* ServerTreeview implements the dynamic tree view.
@@ -51,10 +54,11 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
public messages?: HTMLElement;
private _buttonSection?: HTMLElement;
private _treeSelectionHandler: TreeSelectionHandler;
private _activeConnectionsFilterAction: ActiveConnectionsFilterAction;
private _tree?: ITree | AsyncServerTree;
private _onSelectionOrFocusChange: Emitter<void>;
private _actionProvider: ServerTreeActionProvider;
private _viewKey: IContextKey<ServerTreeViewView>;
private _hasConnectionsKey: IContextKey<boolean>;
constructor(
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@@ -65,14 +69,12 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
@IConfigurationService private _configurationService: IConfigurationService,
@ICapabilitiesService capabilitiesService: ICapabilitiesService,
@IContextMenuService private _contextMenuService: IContextMenuService,
@IKeybindingService private _keybindingService: IKeybindingService
@IKeybindingService private _keybindingService: IKeybindingService,
@IContextKeyService contextKeyService: IContextKeyService
) {
super();
this._activeConnectionsFilterAction = this._instantiationService.createInstance(
ActiveConnectionsFilterAction,
ActiveConnectionsFilterAction.ID,
ActiveConnectionsFilterAction.LABEL,
this);
this._hasConnectionsKey = CONTEXT_SERVER_TREE_HAS_CONNECTIONS.bindTo(contextKeyService);
this._viewKey = CONTEXT_SERVER_TREE_VIEW.bindTo(contextKeyService);
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
this._onSelectionOrFocusChange = new Emitter();
this._actionProvider = this._instantiationService.createInstance(ServerTreeActionProvider);
@@ -93,11 +95,8 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
this.registerCommands();
}
/**
* Get active connections filter action
*/
public get activeConnectionsFilterAction(): ActiveConnectionsFilterAction {
return this._activeConnectionsFilterAction;
public get view(): ServerTreeViewView {
return this._viewKey.get();
}
/**
@@ -146,7 +145,6 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
hide(this.messages);
if (!this._connectionManagementService.hasRegisteredServers()) {
this._activeConnectionsFilterAction.enabled = false;
this._buttonSection = append(container, $('.button-section'));
const connectButton = new Button(this._buttonSection);
connectButton.label = localize('serverTree.addConnection', "Add Connection");
@@ -248,7 +246,6 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
private async handleAddConnectionProfile(newProfile?: IConnectionProfile): Promise<void> {
if (this._buttonSection) {
hide(this._buttonSection);
this._activeConnectionsFilterAction.enabled = true;
}
if (this._tree instanceof AsyncServerTree) {
@@ -369,7 +366,8 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
public async refreshTree(): Promise<void> {
hide(this.messages!);
this.clearOtherActions();
this._viewKey.set(ServerTreeViewView.all);
this._hasConnectionsKey.set(this._connectionManagementService.hasRegisteredServers());
return TreeUpdateUtils.registeredServerUpdate(this._tree!, this._connectionManagementService);
}
@@ -419,10 +417,9 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
/**
* Set tree elements based on the view (recent/active)
*/
public showFilteredTree(view: string): void {
public showFilteredTree(view: ServerTreeViewView): void {
hide(this.messages!);
// Clear other action views if user switched between two views
this.clearOtherActions(view);
this._viewKey.set(view);
const root = TreeUpdateUtils.getTreeInput(this._connectionManagementService);
let treeInput: ConnectionProfileGroup | undefined = undefined;
if (root) {
@@ -466,7 +463,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
}
hide(this.messages!);
// Clear other actions if user searched during other views
this.clearOtherActions();
this._viewKey.set(ServerTreeViewView.all);
// Filter connections based on search
const filteredResults = this.searchConnections(searchString);
if (!filteredResults || filteredResults.length === 0) {
@@ -533,18 +530,6 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
return false;
}
/**
* Clears the toggle icons for active and recent
*/
private clearOtherActions(view?: string) {
if (!view) {
this._activeConnectionsFilterAction.isSet = false;
}
if (view === 'recent') {
this._activeConnectionsFilterAction.isSet = false;
}
}
private onSelected(event: any): void {
this._treeSelectionHandler.onTreeSelect(event, this._tree!, this._connectionManagementService, this._objectExplorerService, () => this._onSelectionOrFocusChange.fire());
this._onSelectionOrFocusChange.fire();

View File

@@ -8,8 +8,7 @@ import * as assert from 'assert';
import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
import {
RefreshAction, EditConnectionAction, AddServerAction, DeleteConnectionAction, DisconnectConnectionAction,
ActiveConnectionsFilterAction, RecentConnectionsFilterAction
RefreshAction, EditConnectionAction, DeleteConnectionAction, DisconnectConnectionAction, ActiveConnectionsFilterAction, AddServerAction
}
from 'sql/workbench/services/objectExplorer/browser/connectionTreeAction';
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
@@ -17,7 +16,7 @@ import { TestErrorMessageService } from 'sql/platform/errorMessage/test/common/t
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { ServerTreeView } from 'sql/workbench/contrib/objectExplorer/browser/serverTreeView';
import * as LocalizedConstants from 'sql/workbench/services/connection/browser/localizedConstants';
import { ObjectExplorerService, ObjectExplorerNodeEventArgs } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
import { ObjectExplorerService, ObjectExplorerNodeEventArgs, ServerTreeViewView } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
import { TreeNode } from 'sql/workbench/services/objectExplorer/common/treeNode';
import { NodeType } from 'sql/workbench/services/objectExplorer/common/nodeType';
import { Emitter, Event } from 'vs/base/common/event';
@@ -263,12 +262,15 @@ suite('SQL Connection Tree Action tests', () => {
return new Promise((resolve) => resolve({}));
});
let serverTreeView = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Strict, undefined, instantiationService.object, undefined, undefined, undefined, undefined, capabilitiesService);
serverTreeView.setup(x => x.showFilteredTree(TypeMoq.It.isAnyString()));
let serverTreeView = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Strict, undefined, instantiationService.object, undefined, undefined, undefined, undefined, capabilitiesService, undefined, undefined, new MockContextKeyService());
serverTreeView.setup(x => x.showFilteredTree(TypeMoq.It.isAny()));
serverTreeView.setup(x => x.refreshTree());
let connectionTreeAction: ActiveConnectionsFilterAction = new ActiveConnectionsFilterAction(ActiveConnectionsFilterAction.ID, ActiveConnectionsFilterAction.LABEL, serverTreeView.object);
serverTreeView.setup(x => x.view).returns(() => ServerTreeViewView.all);
const mockObjectExplorerService = TypeMoq.Mock.ofType(ObjectExplorerService);
mockObjectExplorerService.setup(x => x.getServerTreeView()).returns(() => serverTreeView.object);
let connectionTreeAction: ActiveConnectionsFilterAction = new ActiveConnectionsFilterAction(ActiveConnectionsFilterAction.ID, ActiveConnectionsFilterAction.SHOW_ACTIVE_CONNECTIONS_LABEL, mockObjectExplorerService.object);
return connectionTreeAction.run().then((value) => {
serverTreeView.verify(x => x.showFilteredTree('active'), TypeMoq.Times.once());
serverTreeView.verify(x => x.showFilteredTree(ServerTreeViewView.active), TypeMoq.Times.once());
});
});
@@ -278,42 +280,13 @@ suite('SQL Connection Tree Action tests', () => {
return new Promise((resolve) => resolve({}));
});
let serverTreeView = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Strict, undefined, instantiationService.object, undefined, undefined, undefined, undefined, capabilitiesService);
serverTreeView.setup(x => x.showFilteredTree(TypeMoq.It.isAnyString()));
let serverTreeView = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Strict, undefined, instantiationService.object, undefined, undefined, undefined, undefined, capabilitiesService, undefined, undefined, new MockContextKeyService());
serverTreeView.setup(x => x.showFilteredTree(TypeMoq.It.isAny()));
serverTreeView.setup(x => x.refreshTree());
let connectionTreeAction: ActiveConnectionsFilterAction = new ActiveConnectionsFilterAction(ActiveConnectionsFilterAction.ID, ActiveConnectionsFilterAction.LABEL, serverTreeView.object);
connectionTreeAction.isSet = true;
return connectionTreeAction.run().then((value) => {
serverTreeView.verify(x => x.refreshTree(), TypeMoq.Times.once());
});
});
test('RecentConnectionsFilterAction - test if view is called to display filtered results', () => {
let instantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Loose);
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny())).returns((input) => {
return new Promise((resolve) => resolve({}));
});
let serverTreeView = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Strict, undefined, instantiationService.object, undefined, undefined, undefined, undefined, capabilitiesService);
serverTreeView.setup(x => x.showFilteredTree(TypeMoq.It.isAnyString()));
serverTreeView.setup(x => x.refreshTree());
let connectionTreeAction: RecentConnectionsFilterAction = new RecentConnectionsFilterAction(RecentConnectionsFilterAction.ID, RecentConnectionsFilterAction.LABEL, serverTreeView.object);
return connectionTreeAction.run().then((value) => {
serverTreeView.verify(x => x.showFilteredTree('recent'), TypeMoq.Times.once());
});
});
test('RecentConnectionsFilterAction - test if view is called refresh results if action is toggled', () => {
let instantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Loose);
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny())).returns((input) => {
return new Promise((resolve) => resolve({}));
});
let serverTreeView = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Strict, undefined, instantiationService.object, undefined, undefined, undefined, undefined, capabilitiesService);
serverTreeView.setup(x => x.showFilteredTree(TypeMoq.It.isAnyString()));
serverTreeView.setup(x => x.refreshTree());
let connectionTreeAction: RecentConnectionsFilterAction = new RecentConnectionsFilterAction(RecentConnectionsFilterAction.ID, RecentConnectionsFilterAction.LABEL, serverTreeView.object);
connectionTreeAction.isSet = true;
serverTreeView.setup(x => x.view).returns(() => ServerTreeViewView.active);
const mockObjectExplorerService = TypeMoq.Mock.ofType(ObjectExplorerService);
mockObjectExplorerService.setup(x => x.getServerTreeView()).returns(() => serverTreeView.object);
let connectionTreeAction: ActiveConnectionsFilterAction = new ActiveConnectionsFilterAction(ActiveConnectionsFilterAction.ID, ActiveConnectionsFilterAction.SHOW_ACTIVE_CONNECTIONS_LABEL, mockObjectExplorerService.object);
return connectionTreeAction.run().then((value) => {
serverTreeView.verify(x => x.refreshTree(), TypeMoq.Times.once());
});

View File

@@ -16,6 +16,7 @@ import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServic
import { TreeItemCollapsibleState } from 'sql/workbench/services/objectExplorer/common/treeNode';
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
import * as assert from 'assert';
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
suite('ServerTreeView onAddConnectionProfile handler tests', () => {
@@ -37,7 +38,7 @@ suite('ServerTreeView onAddConnectionProfile handler tests', () => {
);
mockConnectionManagementService.setup(x => x.getConnectionGroups()).returns(x => []);
mockConnectionManagementService.setup(x => x.hasRegisteredServers()).returns(() => true);
serverTreeView = new ServerTreeView(mockConnectionManagementService.object, instantiationService, undefined, new TestThemeService(), undefined, undefined, capabilitiesService, undefined, undefined);
serverTreeView = new ServerTreeView(mockConnectionManagementService.object, instantiationService, undefined, new TestThemeService(), undefined, undefined, capabilitiesService, undefined, undefined, new MockContextKeyService());
mockTree = TypeMoq.Mock.ofType(TestTree);
(serverTreeView as any)._tree = mockTree.object;
mockRefreshTreeMethod = TypeMoq.Mock.ofType(Function);

View File

@@ -22,6 +22,7 @@ import { createObjectExplorerServiceMock } from 'sql/workbench/services/objectEx
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TestTree } from 'sql/workbench/test/treeMock';
import { TestConnectionManagementService } from 'sql/platform/connection/test/common/testConnectionManagementService';
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
const connection: azdata.IConnectionProfile = {
options: [],
@@ -64,7 +65,7 @@ suite('Scripting Actions', () => {
instantiationService = new InstantiationService(collection);
const capabilitiesService = new TestCapabilitiesService();
const connectionManagementServiceMock = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Loose);
const serverTreeViewMock = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Loose, connectionManagementServiceMock.object, instantiationService, undefined, undefined, undefined, undefined, capabilitiesService);
const serverTreeViewMock = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Loose, connectionManagementServiceMock.object, instantiationService, undefined, undefined, undefined, undefined, capabilitiesService, undefined, undefined, new MockContextKeyService());
treeMock = TypeMoq.Mock.ofType(TestTree);
serverTreeViewMock.setup(x => x.tree).returns(() => treeMock.object);
collection.set(IObjectExplorerService, createObjectExplorerServiceMock({ serverTreeView: serverTreeViewMock.object, treeNode: treeNode }));

View File

@@ -3,6 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AddServerAction } from 'sql/workbench/services/objectExplorer/browser/connectionTreeAction';
import { escape } from 'vs/base/common/strings';
import { localize } from 'vs/nls';
@@ -37,7 +38,7 @@ export default () => `
</div>
<div class="row header-bottom-nav-tiles ads-grid">
<div class="col">
<a role="button" class="header-bottom-nav-tile-link ads-welcome-page-link" href="command:registeredServers.addConnection">
<a role="button" class="header-bottom-nav-tile-link ads-welcome-page-link" href="command:${AddServerAction.ID}">
<div class="header-bottom-nav-tile tile tile-connection">
<h3>${escape(localize('welcomePage.createConnection', "Create a connection"))}</h3>
<p>${escape(localize('welcomePage.createConnectionBody', "Connect to a database instance through the connection dialog."))}</p>

View File

@@ -22,8 +22,8 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { Button } from 'sql/base/browser/ui/button/button';
import { extensionsViewIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
import { settingsViewBarIcon } from 'vs/workbench/browser/parts/activitybar/activitybarPart';
import { dataExplorerIconId } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerViewlet';
import { notebookIconId } from 'sql/workbench/contrib/notebook/browser/notebookExplorer/notebookExplorerViewlet';
import { SqlIconId } from 'sql/base/common/codicons';
const $ = dom.$;
interface TourData {
@@ -44,7 +44,7 @@ interface TourData {
popupImage: string;
}
const dataExplorerIconCssSelector = `.action-label.${dataExplorerIconId}`;
const dataExplorerIconCssSelector = `.action-label.${SqlIconId.dataExplorer}`;
const notebookIconCssSelector = `.action-label.${notebookIconId}`;
const extensionsIconCssSelector = ThemeIcon.asCSSSelector(extensionsViewIcon);
const settingsGearIconCssSelector = ThemeIcon.asCSSSelector(settingsViewBarIcon);

View File

@@ -54,6 +54,7 @@ import { ICommandAction, MenuItemAction } from 'vs/platform/actions/common/actio
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IExtensionRecommendationsService } from 'vs/workbench/services/extensionRecommendations/common/extensionRecommendations';
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
import { AddServerAction } from 'sql/workbench/services/objectExplorer/browser/connectionTreeAction';
const configurationKey = 'workbench.startupEditor';
const oldConfigurationKey = 'workbench.welcome.enabled';
const telemetryFrom = 'welcomePage';
@@ -211,7 +212,7 @@ const extensionPackStrings = {
const NewActionItems: ICommandAction[] = [
{
title: localize('welcomePage.newConnection', "New connection"),
id: 'registeredServers.addConnection'
id: AddServerAction.ID
}, {
title: localize('welcomePage.newQuery', "New query"),
id: 'workbench.action.files.newUntitledFile'

View File

@@ -3,6 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AddServerAction } from 'sql/workbench/services/objectExplorer/browser/connectionTreeAction';
import { escape } from 'vs/base/common/strings';
import { localize } from 'vs/nls';
@@ -18,7 +19,7 @@ export default () => `
<div class="section start">
<h2 class="caption">${escape(localize('welcomePage.start', "Start"))}</h2>
<ul>
<li><a href="command:registeredServers.addConnection">${escape(localize('welcomePage.newConnection', "New connection"))}</a></li>
<li><a href="command:${AddServerAction.ID}">${escape(localize('welcomePage.newConnection', "New connection"))}</a></li>
<li><a href="command:workbench.action.files.newUntitledFile">${escape(localize('welcomePage.newQuery', "New query"))}</a></li>
<li><a href="command:notebook.command.new">${escape(localize('welcomePage.newNotebook', "New notebook"))}</a></li>
<li class="mac-only"><a href="command:workbench.action.files.openLocalFileFolder">${escape(localize('welcomePage.openFileMac', "Open file"))}</a></li>

View File

@@ -10,7 +10,7 @@ import { IConnectionManagementService } from 'sql/platform/connection/common/con
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
import { ITree } from 'vs/base/parts/tree/browser/tree';
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
import { IObjectExplorerService, ServerTreeViewView } from 'sql/workbench/services/objectExplorer/browser/objectExplorerService';
import { TreeNode } from 'sql/workbench/services/objectExplorer/common/treeNode';
import Severity from 'vs/base/common/severity';
import { ObjectExplorerActionsContext } from 'sql/workbench/services/objectExplorer/browser/objectExplorerActions';
@@ -19,6 +19,7 @@ import { UNSAVED_GROUP_ID } from 'sql/platform/connection/common/constants';
import { IServerGroupController } from 'sql/platform/serverGroup/common/serverGroupController';
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';
export interface IServerView {
showFilteredTree(filter: string): void;
@@ -158,8 +159,7 @@ export class AddServerAction extends Action {
label: string,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
) {
super(id, label);
this.class = 'add-server-action';
super(id, label, SqlIconId.addServerAction);
}
public async run(element: ConnectionProfileGroup): Promise<boolean> {
@@ -187,7 +187,7 @@ export class AddServerAction extends Action {
}
/**
* Actions to add a server to the group
* Action to open up the dialog to create a new server group
*/
export class AddServerGroupAction extends Action {
public static ID = 'registeredServers.addServerGroup';
@@ -198,8 +198,7 @@ export class AddServerGroupAction extends Action {
label: string,
@IServerGroupController private readonly serverGroupController: IServerGroupController
) {
super(id, label);
this.class = 'add-server-group-action';
super(id, label, SqlIconId.addServerGroupAction);
}
public async run(): Promise<boolean> {
@@ -232,96 +231,33 @@ export class EditServerGroupAction extends Action {
}
/**
* Display active connections in the tree
* Action to toggle filtering the server connections tree to only show
* active connections or not.
*/
export class ActiveConnectionsFilterAction extends Action {
public static ID = 'registeredServers.recentConnections';
public static LABEL = localize('activeConnections', "Show Active Connections");
private static enabledClass = 'active-connections-action';
private static disabledClass = 'icon server-page';
private static showAllConnectionsLabel = localize('showAllConnections', "Show All Connections");
private _isSet: boolean = false;
public static SHOW_ACTIVE_CONNECTIONS_LABEL = localize('activeConnections', "Show Active Connections");
public static SHOW_ALL_CONNECTIONS_LABEL = localize('showAllConnections', "Show All Connections");
public static readonly ACTIVE = 'active';
public get isSet(): boolean {
return this._isSet;
}
public set isSet(value: boolean) {
this._isSet = value;
this.class = (!this._isSet) ?
ActiveConnectionsFilterAction.enabledClass : ActiveConnectionsFilterAction.disabledClass;
}
constructor(
id: string,
label: string,
private view: IServerView
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService
) {
super(id, label);
this.class = ActiveConnectionsFilterAction.enabledClass;
super(id, label, SqlIconId.activeConnectionsAction);
}
public run(): Promise<boolean> {
if (!this.view) {
// return without doing anything
return Promise.resolve(true);
}
if (this.class === ActiveConnectionsFilterAction.enabledClass) {
public async run(): Promise<boolean> {
const serverTreeView = this._objectExplorerService.getServerTreeView();
if (serverTreeView.view !== ServerTreeViewView.active) {
// show active connections in the tree
this.view.showFilteredTree(ActiveConnectionsFilterAction.ACTIVE);
this.isSet = true;
this.label = ActiveConnectionsFilterAction.showAllConnectionsLabel;
serverTreeView.showFilteredTree(ServerTreeViewView.active);
} else {
// show full tree
this.view.refreshTree();
this.isSet = false;
this.label = ActiveConnectionsFilterAction.LABEL;
await serverTreeView.refreshTree();
}
return Promise.resolve(true);
}
}
/**
* Display recent connections in the tree
*/
export class RecentConnectionsFilterAction extends Action {
public static ID = 'registeredServers.recentConnections';
public static LABEL = localize('recentConnections', "Recent Connections");
private static enabledClass = 'recent-connections-action';
private static disabledClass = 'recent-connections-action-set';
private _isSet: boolean;
public get isSet(): boolean {
return this._isSet;
}
public set isSet(value: boolean) {
this._isSet = value;
this.class = (!this._isSet) ?
RecentConnectionsFilterAction.enabledClass : RecentConnectionsFilterAction.disabledClass;
}
constructor(
id: string,
label: string,
private view: IServerView
) {
super(id, label);
this.class = RecentConnectionsFilterAction.enabledClass;
this._isSet = false;
}
public run(): Promise<boolean> {
if (!this.view) {
// return without doing anything
return Promise.resolve(true);
}
if (this.class === RecentConnectionsFilterAction.enabledClass) {
// show recent connections in the tree
this.view.showFilteredTree('recent');
this.isSet = true;
} else {
// show full tree
this.view.refreshTree();
this.isSet = false;
}
return Promise.resolve(true);
return true;
}
}

View File

@@ -20,7 +20,6 @@ import { entries } from 'sql/base/common/collections';
import { values } from 'vs/base/common/collections';
import { startsWith } from 'vs/base/common/strings';
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
import { IAction } from 'vs/base/common/actions';
import { ServerTreeActionProvider } from 'sql/workbench/services/objectExplorer/browser/serverTreeActionProvider';
import { ITree } from 'vs/base/parts/tree/browser/tree';
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
@@ -33,6 +32,11 @@ export interface NodeExpandInfoWithProviderId extends azdata.ObjectExplorerExpan
providerId: string;
}
export const enum ServerTreeViewView {
all = 'all',
active = 'active'
}
export interface IServerTreeView {
readonly tree: ITree | AsyncServerTree;
readonly onSelectionOrFocusChange: Event<void>;
@@ -47,9 +51,10 @@ export interface IServerTreeView {
setExpandedState(node: ServerTreeElement, state?: TreeItemCollapsibleState): Promise<void>;
setSelected(node: ServerTreeElement, selected?: boolean, clearOtherSelections?: boolean): Promise<void>;
refreshTree(): Promise<void>;
readonly activeConnectionsFilterAction: IAction;
renderBody(container: HTMLElement): Promise<void>;
layout(size: number): void;
showFilteredTree(view: ServerTreeViewView): void;
view: ServerTreeViewView;
}
export interface IObjectExplorerService {

View File

@@ -9,8 +9,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import {
DisconnectConnectionAction, AddServerAction, EditConnectionAction,
DeleteConnectionAction, RefreshAction, EditServerGroupAction
DisconnectConnectionAction, EditConnectionAction,
DeleteConnectionAction, RefreshAction, EditServerGroupAction, AddServerAction
} 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';
@@ -157,6 +157,7 @@ export class ServerTreeActionProvider {
* Return actions for connection group elements
*/
private getConnectionProfileGroupActions(element: ConnectionProfileGroup): IAction[] {
// TODO: Should look into using the MenuRegistry for this
return [
this._instantiationService.createInstance(AddServerAction, AddServerAction.ID, AddServerAction.LABEL),
this._instantiationService.createInstance(EditServerGroupAction, EditServerGroupAction.ID, EditServerGroupAction.LABEL, element),