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

@@ -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);