mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
add sorting option for saved connections (#15229)
* add sort by name option for saved connections and groups
This commit is contained in:
@@ -14,8 +14,14 @@ import * as nls from 'vs/nls';
|
|||||||
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { deepClone } from 'vs/base/common/objects';
|
import { deepClone } from 'vs/base/common/objects';
|
||||||
|
|
||||||
const GROUPS_CONFIG_KEY = 'datasource.connectionGroups';
|
export const GROUPS_CONFIG_KEY = 'datasource.connectionGroups';
|
||||||
const CONNECTIONS_CONFIG_KEY = 'datasource.connections';
|
export const CONNECTIONS_CONFIG_KEY = 'datasource.connections';
|
||||||
|
export const CONNECTIONS_SORT_BY_CONFIG_KEY = 'datasource.connections.sortBy';
|
||||||
|
|
||||||
|
export const enum ConnectionsSortBy {
|
||||||
|
dateAdded = 'dateAdded',
|
||||||
|
displayName = 'displayName'
|
||||||
|
}
|
||||||
|
|
||||||
export interface ISaveGroupResult {
|
export interface ISaveGroupResult {
|
||||||
groups: IConnectionProfileGroup[];
|
groups: IConnectionProfileGroup[];
|
||||||
@@ -49,6 +55,26 @@ export class ConnectionConfig {
|
|||||||
}
|
}
|
||||||
allGroups = allGroups.concat(userValue);
|
allGroups = allGroups.concat(userValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sortBy = this.configurationService.getValue<string>(CONNECTIONS_SORT_BY_CONFIG_KEY);
|
||||||
|
let sortFunc: (a: IConnectionProfileGroup, b: IConnectionProfileGroup) => number;
|
||||||
|
|
||||||
|
if (sortBy === ConnectionsSortBy.displayName) {
|
||||||
|
sortFunc = ((a, b) => {
|
||||||
|
if (a.name < b.name) {
|
||||||
|
return -1;
|
||||||
|
} else if (a.name > b.name) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sortFunc) {
|
||||||
|
allGroups.sort(sortFunc);
|
||||||
|
}
|
||||||
|
|
||||||
return deepClone(allGroups).map(g => {
|
return deepClone(allGroups).map(g => {
|
||||||
if (g.parentId === '' || !g.parentId) {
|
if (g.parentId === '' || !g.parentId) {
|
||||||
g.parentId = undefined;
|
g.parentId = undefined;
|
||||||
@@ -214,6 +240,25 @@ export class ConnectionConfig {
|
|||||||
return ConnectionProfile.createFromStoredProfile(p, this._capabilitiesService);
|
return ConnectionProfile.createFromStoredProfile(p, this._capabilitiesService);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const sortBy = this.configurationService.getValue<string>(CONNECTIONS_SORT_BY_CONFIG_KEY);
|
||||||
|
let sortFunc: (a: ConnectionProfile, b: ConnectionProfile) => number;
|
||||||
|
|
||||||
|
if (sortBy === ConnectionsSortBy.displayName) {
|
||||||
|
sortFunc = ((a, b) => {
|
||||||
|
if (a.title < b.title) {
|
||||||
|
return -1;
|
||||||
|
} else if (a.title > b.title) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sortFunc) {
|
||||||
|
connectionProfiles.sort(sortFunc);
|
||||||
|
}
|
||||||
|
|
||||||
return connectionProfiles;
|
return connectionProfiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { ProviderFeatures } from 'sql/platform/capabilities/common/capabilitiesService';
|
import { ProviderFeatures } from 'sql/platform/capabilities/common/capabilitiesService';
|
||||||
import { ConnectionConfig, ISaveGroupResult } from 'sql/platform/connection/common/connectionConfig';
|
import { ConnectionConfig, ISaveGroupResult, CONNECTIONS_SORT_BY_CONFIG_KEY, ConnectionsSortBy } from 'sql/platform/connection/common/connectionConfig';
|
||||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||||
import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
|
import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
|
||||||
import { IConnectionProfile, IConnectionProfileStore, ConnectionOptionSpecialType, ServiceOptionType } from 'sql/platform/connection/common/interfaces';
|
import { IConnectionProfile, IConnectionProfileStore, ConnectionOptionSpecialType, ServiceOptionType } from 'sql/platform/connection/common/interfaces';
|
||||||
@@ -239,6 +239,33 @@ suite('ConnectionConfig', () => {
|
|||||||
assert.ok(groupsAreEqual(allGroups, testGroups), 'the groups returned did not match expectation');
|
assert.ok(groupsAreEqual(allGroups, testGroups), 'the groups returned did not match expectation');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('getAllGroups should return groups sorted alphabetically by display name given datasource.connections.sortBy is set to \'' + ConnectionsSortBy.displayName + '\'', () => {
|
||||||
|
let configurationService = new TestConfigurationService();
|
||||||
|
configurationService.updateValue('datasource.connectionGroups', deepClone(testGroups).slice(0, 3), ConfigurationTarget.USER);
|
||||||
|
configurationService.updateValue('datasource.connectionGroups', deepClone(testGroups).slice(2, testGroups.length), ConfigurationTarget.WORKSPACE);
|
||||||
|
configurationService.updateValue(CONNECTIONS_SORT_BY_CONFIG_KEY, ConnectionsSortBy.displayName, ConfigurationTarget.USER);
|
||||||
|
|
||||||
|
let config = new ConnectionConfig(configurationService, capabilitiesService.object);
|
||||||
|
let allGroups = config.getAllGroups();
|
||||||
|
|
||||||
|
assert.equal(allGroups.length, testGroups.length, 'did not meet the expected length');
|
||||||
|
assert.ok(groupsAreEqual(allGroups, testGroups), 'the groups returned did not match expectation');
|
||||||
|
assert.ok(allGroups.slice(1).every((item, i) => allGroups[i].name <= item.name), 'the groups are not sorted correctly');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getAllGroups should return groups sorted by date added given datasource.connections.sortBy is set to \'' + ConnectionsSortBy.dateAdded + '\'', () => {
|
||||||
|
let configurationService = new TestConfigurationService();
|
||||||
|
configurationService.updateValue('datasource.connectionGroups', deepClone(testGroups).slice(0, 3).reverse(), ConfigurationTarget.USER);
|
||||||
|
configurationService.updateValue('datasource.connectionGroups', deepClone(testGroups).slice(2, testGroups.length).reverse(), ConfigurationTarget.WORKSPACE);
|
||||||
|
configurationService.updateValue(CONNECTIONS_SORT_BY_CONFIG_KEY, ConnectionsSortBy.dateAdded, ConfigurationTarget.USER);
|
||||||
|
|
||||||
|
let config = new ConnectionConfig(configurationService, capabilitiesService.object);
|
||||||
|
let allGroups = config.getAllGroups();
|
||||||
|
let expectedGroups = deepClone(testGroups).slice(0, 3).reverse().concat(deepClone(testGroups).slice(3, testGroups.length).reverse());
|
||||||
|
assert.equal(allGroups.length, expectedGroups.length, 'The result groups length is invalid');
|
||||||
|
assert.ok(allGroups.every((item, i) => item.id === allGroups[i].id));
|
||||||
|
});
|
||||||
|
|
||||||
test('addConnection should add the new profile to user settings', async () => {
|
test('addConnection should add the new profile to user settings', async () => {
|
||||||
let newProfile: IConnectionProfile = {
|
let newProfile: IConnectionProfile = {
|
||||||
serverName: 'new server',
|
serverName: 'new server',
|
||||||
@@ -384,6 +411,30 @@ suite('ConnectionConfig', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('getConnections should return connections sorted alphabetically by title given datasource.connections.sortBy is set to \'' + ConnectionsSortBy.displayName + '\'', () => {
|
||||||
|
let configurationService = new TestConfigurationService();
|
||||||
|
configurationService.updateValue('datasource.connections', deepClone(testConnections).slice(0, 2).reverse(), ConfigurationTarget.USER);
|
||||||
|
configurationService.updateValue('datasource.connections', deepClone(testConnections).slice(2, testConnections.length).reverse(), ConfigurationTarget.WORKSPACE);
|
||||||
|
configurationService.updateValue(CONNECTIONS_SORT_BY_CONFIG_KEY, ConnectionsSortBy.displayName, ConfigurationTarget.USER);
|
||||||
|
|
||||||
|
let config = new ConnectionConfig(configurationService, capabilitiesService.object);
|
||||||
|
let allConnections = config.getConnections(true);
|
||||||
|
assert.equal(allConnections.length, testConnections.length, 'The result connections length is invalid');
|
||||||
|
assert.ok(allConnections.slice(1).every((item, i) => allConnections[i].title <= item.title), 'The connections are not sorted correctly');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getConnections should return connections sorted by date added given datasource.connections.sortBy is set to \'' + ConnectionsSortBy.dateAdded + '\'', () => {
|
||||||
|
let configurationService = new TestConfigurationService();
|
||||||
|
configurationService.updateValue('datasource.connections', deepClone(testConnections).reverse(), ConfigurationTarget.USER);
|
||||||
|
configurationService.updateValue(CONNECTIONS_SORT_BY_CONFIG_KEY, ConnectionsSortBy.dateAdded, ConfigurationTarget.USER);
|
||||||
|
|
||||||
|
let config = new ConnectionConfig(configurationService, capabilitiesService.object);
|
||||||
|
let allConnections = config.getConnections(false);
|
||||||
|
let expectedConnections = deepClone(testConnections).reverse();
|
||||||
|
assert.equal(allConnections.length, expectedConnections.length, 'The result connections length is invalid');
|
||||||
|
assert.ok(allConnections.every((item, i) => item.id === expectedConnections[i].id));
|
||||||
|
});
|
||||||
|
|
||||||
test('saveGroup should save the new groups to tree and return the id of the last group name', () => {
|
test('saveGroup should save the new groups to tree and return the id of the last group name', () => {
|
||||||
let config = new ConnectionConfig(undefined!, undefined!);
|
let config = new ConnectionConfig(undefined!, undefined!);
|
||||||
let groups: IConnectionProfileGroup[] = deepClone(testGroups);
|
let groups: IConnectionProfileGroup[] = deepClone(testGroups);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/co
|
|||||||
import { DataExplorerContainerExtensionHandler } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerExtensionPoint';
|
import { DataExplorerContainerExtensionHandler } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerExtensionPoint';
|
||||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||||
import { DataExplorerViewletViewsContribution } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerViewlet';
|
import { DataExplorerViewletViewsContribution } from 'sql/workbench/contrib/dataExplorer/browser/dataExplorerViewlet';
|
||||||
|
import { GROUPS_CONFIG_KEY, CONNECTIONS_CONFIG_KEY, CONNECTIONS_SORT_BY_CONFIG_KEY, ConnectionsSortBy } from 'sql/platform/connection/common/connectionConfig';
|
||||||
|
|
||||||
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||||
workbenchRegistry.registerWorkbenchContribution(DataExplorerViewletViewsContribution, LifecyclePhase.Starting);
|
workbenchRegistry.registerWorkbenchContribution(DataExplorerViewletViewsContribution, LifecyclePhase.Starting);
|
||||||
@@ -22,13 +23,23 @@ configurationRegistry.registerConfiguration({
|
|||||||
'title': localize('databaseConnections', "Database Connections"),
|
'title': localize('databaseConnections', "Database Connections"),
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
'datasource.connections': {
|
[CONNECTIONS_CONFIG_KEY]: {
|
||||||
'description': localize('datasource.connections', "data source connections"),
|
'description': localize('datasource.connections', "data source connections"),
|
||||||
'type': 'array'
|
'type': 'array'
|
||||||
},
|
},
|
||||||
'datasource.connectionGroups': {
|
[GROUPS_CONFIG_KEY]: {
|
||||||
'description': localize('datasource.connectionGroups', "data source groups"),
|
'description': localize('datasource.connectionGroups', "data source groups"),
|
||||||
'type': 'array'
|
'type': 'array'
|
||||||
|
},
|
||||||
|
[CONNECTIONS_SORT_BY_CONFIG_KEY]: {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': [ConnectionsSortBy.dateAdded, ConnectionsSortBy.displayName],
|
||||||
|
'enumDescriptions': [
|
||||||
|
localize('connections.sortBy.dateAdded', 'Saved connections are sorted by the dates they were added.'),
|
||||||
|
localize('connections.sortBy.displayName', 'Saved connections are sorted by their display names alphabetically.')
|
||||||
|
],
|
||||||
|
'default': ConnectionsSortBy.dateAdded,
|
||||||
|
'description': localize('datasource.connections.sortBy', "Order used for sorting saved connections and connection groups")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
|||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
|
import { AsyncServerTree, ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
|
||||||
import { coalesce } from 'vs/base/common/arrays';
|
import { coalesce } from 'vs/base/common/arrays';
|
||||||
|
import { CONNECTIONS_SORT_BY_CONFIG_KEY } from 'sql/platform/connection/common/connectionConfig';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ServerTreeview implements the dynamic tree view.
|
* ServerTreeview implements the dynamic tree view.
|
||||||
@@ -196,6 +197,11 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
|
|||||||
this.deleteObjectExplorerNodeAndRefreshTree(connectionParams.connectionProfile).catch(errors.onUnexpectedError);
|
this.deleteObjectExplorerNodeAndRefreshTree(connectionParams.connectionProfile).catch(errors.onUnexpectedError);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
this._register(this._configurationService.onDidChangeConfiguration(e => {
|
||||||
|
if (e.affectsConfiguration(CONNECTIONS_SORT_BY_CONFIG_KEY)) {
|
||||||
|
this.refreshTree().catch(err => errors.onUnexpectedError);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
if (this._objectExplorerService && this._objectExplorerService.onUpdateObjectExplorerNodes) {
|
if (this._objectExplorerService && this._objectExplorerService.onUpdateObjectExplorerNodes) {
|
||||||
this._register(this._objectExplorerService.onUpdateObjectExplorerNodes(args => {
|
this._register(this._objectExplorerService.onUpdateObjectExplorerNodes(args => {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { ConnectionProfile } from 'sql/platform/connection/common/connectionProf
|
|||||||
import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
|
import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup';
|
||||||
import { attachInputBoxStyler } from 'sql/platform/theme/common/styler';
|
import { attachInputBoxStyler } from 'sql/platform/theme/common/styler';
|
||||||
import { ITreeItem } from 'sql/workbench/common/views';
|
import { ITreeItem } from 'sql/workbench/common/views';
|
||||||
|
import { CONNECTIONS_SORT_BY_CONFIG_KEY } from 'sql/platform/connection/common/connectionConfig';
|
||||||
import { IConnectionTreeDescriptor, IConnectionTreeService } from 'sql/workbench/services/connection/common/connectionTreeService';
|
import { IConnectionTreeDescriptor, IConnectionTreeService } from 'sql/workbench/services/connection/common/connectionTreeService';
|
||||||
import { AsyncRecentConnectionTreeDataSource } from 'sql/workbench/services/objectExplorer/browser/asyncRecentConnectionTreeDataSource';
|
import { AsyncRecentConnectionTreeDataSource } from 'sql/workbench/services/objectExplorer/browser/asyncRecentConnectionTreeDataSource';
|
||||||
import { ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
|
import { ServerTreeElement } from 'sql/workbench/services/objectExplorer/browser/asyncServerTree';
|
||||||
@@ -91,7 +92,8 @@ export class ConnectionBrowserView extends Disposable implements IPanelView {
|
|||||||
@ICommandService private readonly commandService: ICommandService,
|
@ICommandService private readonly commandService: ICommandService,
|
||||||
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
@IContextMenuService private readonly contextMenuService: IContextMenuService,
|
||||||
@IConnectionManagementService private readonly connectionManagementService: IConnectionManagementService,
|
@IConnectionManagementService private readonly connectionManagementService: IConnectionManagementService,
|
||||||
@ICapabilitiesService private readonly capabilitiesService: ICapabilitiesService
|
@ICapabilitiesService private readonly capabilitiesService: ICapabilitiesService,
|
||||||
|
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.connectionTreeService.setView(this);
|
this.connectionTreeService.setView(this);
|
||||||
@@ -224,6 +226,13 @@ export class ConnectionBrowserView extends Disposable implements IPanelView {
|
|||||||
this._register(this.themeService.onDidColorThemeChange(async () => {
|
this._register(this.themeService.onDidColorThemeChange(async () => {
|
||||||
await this.refresh();
|
await this.refresh();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
||||||
|
if (e.affectsConfiguration(CONNECTIONS_SORT_BY_CONFIG_KEY)) {
|
||||||
|
this.updateSavedConnectionsNode();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleTreeElementSelection(selectedNode: TreeElement, connect: boolean): void {
|
private handleTreeElementSelection(selectedNode: TreeElement, connect: boolean): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user