Export function to prompt user to select/create connection (#17010)

* Export function to prompt user to select/create connection

* change name

* update typings

* Fix compile-view
This commit is contained in:
Charles Gagnon 2021-07-18 19:40:24 -07:00 коммит произвёл GitHub
Родитель d2284a9897
Коммит b2201cebda
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
20 изменённых файлов: 335 добавлений и 343 удалений

Просмотреть файл

@ -77,7 +77,8 @@ gulp.task('ext:compile-src', (done) => {
// Compile angular view
gulp.task('ext:compile-view', (done) => {
return gulp.src([
config.paths.project.root + '/src/views/htmlcontent/**/*.ts'])
config.paths.project.root + '/src/views/htmlcontent/**/*.ts',
config.paths.project.root + '/typings/**/*.d.ts'])
.pipe(srcmap.init())
.pipe(tsProject())
.pipe(nls.rewriteLocalizeCalls())

Просмотреть файл

@ -22,13 +22,14 @@ import { Runtime, PlatformInformation } from '../models/platform';
import { Deferred } from '../protocol';
import { AccountService } from '../azure/accountService';
import { FirewallService } from '../firewall/firewallService';
import { IConnectionCredentials, IConnectionProfile } from '../models/interfaces';
import { IConnectionProfile } from '../models/interfaces';
import { ConnectionSummary } from '../models/contracts/connection';
import { AccountStore } from '../azure/accountStore';
import { ConnectionProfile } from '../models/connectionProfile';
import { QuestionTypes, IQuestion } from '../prompts/question';
import { IAccount } from '../models/contracts/azure/accountInterfaces';
import { AzureController } from '../azure/azureController';
import { IConnectionInfo } from 'vscode-mssql';
/**
* Information for a document's connection. Exported for testing purposes.
@ -42,7 +43,7 @@ export class ConnectionInfo {
/**
* Credentials used to connect
*/
public credentials: IConnectionCredentials;
public credentials: IConnectionInfo;
/**
* Callback for when a connection notification is received.
@ -79,7 +80,7 @@ export default class ConnectionManager {
private _statusView: StatusView;
private _connections: { [fileUri: string]: ConnectionInfo };
private _connectionCredentialsToServerInfoMap:
Map<IConnectionCredentials, ConnectionContracts.ServerInfo>;
Map<IConnectionInfo, ConnectionContracts.ServerInfo>;
private _uriToConnectionPromiseMap: Map<string, Deferred<boolean>>;
private _failedUriToFirewallIpMap: Map<string, string>;
private _accountService: AccountService;
@ -97,7 +98,7 @@ export default class ConnectionManager {
this._statusView = statusView;
this._connections = {};
this._connectionCredentialsToServerInfoMap =
new Map<IConnectionCredentials, ConnectionContracts.ServerInfo>();
new Map<IConnectionInfo, ConnectionContracts.ServerInfo>();
this._uriToConnectionPromiseMap = new Map<string, Deferred<boolean>>();
@ -233,7 +234,7 @@ export default class ConnectionManager {
return this._firewallService;
}
public isActiveConnection(credential: IConnectionCredentials): boolean {
public isActiveConnection(credential: IConnectionInfo): boolean {
const connectedCredentials = Object.keys(this._connections).map((uri) => this._connections[uri].credentials);
for (let connectedCredential of connectedCredentials) {
if (Utils.isSameConnection(credential, connectedCredential)) {
@ -243,7 +244,7 @@ export default class ConnectionManager {
return false;
}
public getUriForConnection(connection: IConnectionCredentials): string {
public getUriForConnection(connection: IConnectionInfo): string {
for (let uri of Object.keys(this._connections)) {
if (Utils.isSameConnection(this._connections[uri].credentials, connection)) {
return uri;
@ -319,7 +320,7 @@ export default class ConnectionManager {
let connection = self.getConnectionInfo(fileUri);
connection.connecting = false;
let mruConnection: IConnectionCredentials = <any>{};
let mruConnection: IConnectionInfo = <any>{};
if (Utils.isNotEmpty(result.connectionId)) {
// Convert to credentials if it's a connection string based connection
@ -330,8 +331,8 @@ export default class ConnectionManager {
// We have a valid connection
// Copy credentials as the database name will be updated
let newCredentials: IConnectionCredentials = <any>{};
Object.assign<IConnectionCredentials, IConnectionCredentials>(newCredentials, connection.credentials);
let newCredentials: IConnectionInfo = <any>{};
Object.assign<IConnectionInfo, IConnectionInfo>(newCredentials, connection.credentials);
if (result.connectionSummary && result.connectionSummary.databaseName) {
newCredentials.database = result.connectionSummary.databaseName;
}
@ -365,7 +366,7 @@ export default class ConnectionManager {
private handleConnectionSuccess(fileUri: string,
connection: ConnectionInfo,
newCredentials: IConnectionCredentials,
newCredentials: IConnectionInfo,
result: ConnectionContracts.ConnectionCompleteParams): void {
connection.connectionId = result.connectionId;
connection.serverInfo = result.serverInfo;
@ -426,9 +427,9 @@ export default class ConnectionManager {
);
}
private async tryAddMruConnection(connection: ConnectionInfo, newConnection: IConnectionCredentials): Promise<void> {
private async tryAddMruConnection(connection: ConnectionInfo, newConnection: IConnectionInfo): Promise<void> {
if (newConnection) {
let connectionToSave: IConnectionCredentials = Object.assign({}, newConnection);
let connectionToSave: IConnectionInfo = Object.assign({}, newConnection);
try {
await this._connectionStore.addRecentlyUsed(connectionToSave);
connection.connectHandler(true);
@ -443,7 +444,7 @@ export default class ConnectionManager {
/**
* Populates a credential object based on the credential connection string
*/
private populateCredentialsFromConnectionString(credentials: IConnectionCredentials, connectionSummary: ConnectionSummary): IConnectionCredentials {
private populateCredentialsFromConnectionString(credentials: IConnectionInfo, connectionSummary: ConnectionSummary): IConnectionInfo {
// populate credential details
credentials.database = connectionSummary.databaseName;
credentials.user = connectionSummary.userName;
@ -510,7 +511,7 @@ export default class ConnectionManager {
}
}
public async changeDatabase(newDatabaseCredentials: IConnectionCredentials): Promise<boolean> {
public async changeDatabase(newDatabaseCredentials: IConnectionInfo): Promise<boolean> {
const fileUri = this.vscodeWrapper.activeTextEditorUri;
if (!this.isConnected(fileUri)) {
this.vscodeWrapper.showWarningMessage(LocalizedConstants.msgChooseDatabaseNotConnected);
@ -591,9 +592,9 @@ export default class ConnectionManager {
/**
* Helper to show all connections and perform connect logic.
*/
public async showConnectionsAndConnect(fileUri: string): Promise<IConnectionCredentials> {
public async showConnectionsAndConnect(fileUri: string): Promise<IConnectionInfo> {
// show connection picklist
const connectionCreds = await this.connectionUI.showConnections();
const connectionCreds = await this.connectionUI.promptForConnection();
if (connectionCreds) {
// close active connection
await this.disconnect(fileUri);
@ -608,7 +609,7 @@ export default class ConnectionManager {
* Get the server info for a connection
* @param connectionCreds
*/
public getServerInfo(connectionCredentials: IConnectionCredentials): ConnectionContracts.ServerInfo {
public getServerInfo(connectionCredentials: IConnectionInfo): ConnectionContracts.ServerInfo {
if (this._connectionCredentialsToServerInfoMap.has(connectionCredentials)) {
return this._connectionCredentialsToServerInfoMap.get(connectionCredentials);
}
@ -621,7 +622,7 @@ export default class ConnectionManager {
* @param fileUri file Uri
* @param connectionCreds Connection Profile
*/
private async handleConnectionResult(result: boolean, fileUri: string, connectionCreds: IConnectionCredentials): Promise<boolean> {
private async handleConnectionResult(result: boolean, fileUri: string, connectionCreds: IConnectionInfo): Promise<boolean> {
let connection = this._connections[fileUri];
if (!result && connection && connection.loginFailed) {
const newConnection = await this.connectionUI.createProfileWithDifferentCredentials(connectionCreds);
@ -648,7 +649,7 @@ export default class ConnectionManager {
}
// let users pick from a picklist of connections
public async onNewConnection(): Promise<IConnectionCredentials> {
public async onNewConnection(): Promise<IConnectionInfo> {
const fileUri = this.vscodeWrapper.activeTextEditorUri;
if (!fileUri) {
// A text document needs to be open before we can connect
@ -668,7 +669,7 @@ export default class ConnectionManager {
}
// create a new connection with the connectionCreds provided
public async connect(fileUri: string, connectionCreds: IConnectionCredentials, promise?: Deferred<boolean>): Promise<boolean> {
public async connect(fileUri: string, connectionCreds: IConnectionInfo, promise?: Deferred<boolean>): Promise<boolean> {
const self = this;
let connectionPromise = new Promise<boolean>(async (resolve, reject) => {
let connectionInfo: ConnectionInfo = new ConnectionInfo();
@ -783,7 +784,7 @@ export default class ConnectionManager {
}
// Connect the saved uri and disconnect the untitled uri on successful connection
let creds: IConnectionCredentials = this._connections[oldFileUri].credentials;
let creds: IConnectionInfo = this._connections[oldFileUri].credentials;
let result = await this.connect(newFileUri, creds);
if (result) {
await this.disconnect(oldFileUri);

Просмотреть файл

@ -18,7 +18,7 @@ import { IPrompter } from '../prompts/question';
import CodeAdapter from '../prompts/adapter';
import VscodeWrapper from './vscodeWrapper';
import UntitledSqlDocumentService from './untitledSqlDocumentService';
import { ISelectionData, IConnectionProfile, IConnectionCredentials } from './../models/interfaces';
import { ISelectionData, IConnectionProfile } from './../models/interfaces';
import * as path from 'path';
import fs = require('fs');
import { ObjectExplorerProvider } from '../objectExplorer/objectExplorerProvider';
@ -32,6 +32,7 @@ import { ScriptOperation } from '../models/contracts/scripting/scriptingRequest'
import { QueryHistoryProvider } from '../queryHistory/queryHistoryProvider';
import { QueryHistoryNode } from '../queryHistory/queryHistoryNode';
import { DacFxService } from '../dacFxService/dacFxService';
import { IConnectionInfo } from 'vscode-mssql';
/**
* The main controller class that initializes the extension
@ -258,7 +259,7 @@ export default class MainController implements vscode.Disposable {
/**
* Creates a new Object Explorer session
*/
private async createObjectExplorerSession(connectionCredentials?: IConnectionCredentials): Promise<void> {
private async createObjectExplorerSession(connectionCredentials?: IConnectionInfo): Promise<void> {
let createSessionPromise = new Deferred<TreeNodeInfo>();
const sessionId = await this._objectExplorerProvider.createSession(createSessionPromise, connectionCredentials, this._context);
if (sessionId) {
@ -339,7 +340,7 @@ export default class MainController implements vscode.Disposable {
let profile = <IConnectionProfile>node.parentNode.connectionCredentials;
profile = await self.connectionManager.connectionUI.promptForRetryCreateProfile(profile);
if (profile) {
node.parentNode.connectionCredentials = <IConnectionCredentials>profile;
node.parentNode.connectionCredentials = <IConnectionInfo>profile;
self._objectExplorerProvider.updateNode(node.parentNode);
self._objectExplorerProvider.signInNodeServer(node.parentNode);
return self._objectExplorerProvider.refresh(undefined);

Просмотреть файл

@ -29,6 +29,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
vscode.commands.registerCommand('mssql.getControllerForTests', () => controller);
await controller.activate();
return {
promptForConnection: () => {
return controller.connectionManager.connectionUI.promptForConnection();
},
dacFx: controller.dacFxService
};
}

Просмотреть файл

@ -6,14 +6,15 @@
'use strict';
import LocalizedConstants = require('../constants/localizedConstants');
import { ConnectionDetails } from './contracts/connection';
import { IConnectionCredentials, IConnectionProfile, AuthenticationTypes } from './interfaces';
import { IConnectionProfile, AuthenticationTypes } from './interfaces';
import { ConnectionStore } from './connectionStore';
import * as utils from './utils';
import { QuestionTypes, IQuestion, IPrompter, INameValueChoice } from '../prompts/question';
import SqlToolsServerClient from '../languageservice/serviceclient';
import { IConnectionInfo } from 'vscode-mssql';
// Concrete implementation of the IConnectionCredentials interface
export class ConnectionCredentials implements IConnectionCredentials {
export class ConnectionCredentials implements IConnectionInfo {
public server: string;
public database: string;
public user: string;
@ -50,7 +51,7 @@ export class ConnectionCredentials implements IConnectionCredentials {
/**
* Create a connection details contract from connection credentials.
*/
public static createConnectionDetails(credentials: IConnectionCredentials): ConnectionDetails {
public static createConnectionDetails(credentials: IConnectionInfo): ConnectionDetails {
let details: ConnectionDetails = new ConnectionDetails();
details.options['connectionString'] = credentials.connectionString;
@ -91,17 +92,17 @@ export class ConnectionCredentials implements IConnectionCredentials {
}
public static async ensureRequiredPropertiesSet(
credentials: IConnectionCredentials,
credentials: IConnectionInfo,
isProfile: boolean,
isPasswordRequired: boolean,
wasPasswordEmptyInConfigFile: boolean,
prompter: IPrompter,
connectionStore: ConnectionStore,
defaultProfileValues?: IConnectionCredentials): Promise<IConnectionCredentials> {
defaultProfileValues?: IConnectionInfo): Promise<IConnectionInfo> {
let questions: IQuestion[] = await ConnectionCredentials.getRequiredCredentialValuesQuestions(credentials, false,
isPasswordRequired, connectionStore, defaultProfileValues);
let unprocessedCredentials: IConnectionCredentials = Object.assign({}, credentials);
let unprocessedCredentials: IConnectionInfo = Object.assign({}, credentials);
// Potentially ask to save password
questions.push({
@ -160,11 +161,11 @@ export class ConnectionCredentials implements IConnectionCredentials {
// gets a set of questions that ensure all required and core values are set
protected static async getRequiredCredentialValuesQuestions(
credentials: IConnectionCredentials,
credentials: IConnectionInfo,
promptForDbName: boolean,
isPasswordRequired: boolean,
connectionStore: ConnectionStore,
defaultProfileValues?: IConnectionCredentials): Promise<IQuestion[]> {
defaultProfileValues?: IConnectionInfo): Promise<IQuestion[]> {
let authenticationChoices: INameValueChoice[] = ConnectionCredentials.getAuthenticationTypesChoice();
@ -252,7 +253,7 @@ export class ConnectionCredentials implements IConnectionCredentials {
}
// Detect if a given value is a server name or a connection string, and assign the result accordingly
private static processServerOrConnectionString(value: string, credentials: IConnectionCredentials): void {
private static processServerOrConnectionString(value: string, credentials: IConnectionInfo): void {
// If the value contains a connection string server name key, assume it is a connection string
const dataSourceKeys = ['data source=', 'server=', 'address=', 'addr=', 'network address='];
let isConnectionString = dataSourceKeys.some(key => value.toLowerCase().indexOf(key) !== -1);
@ -264,13 +265,13 @@ export class ConnectionCredentials implements IConnectionCredentials {
}
}
private static shouldPromptForUser(credentials: IConnectionCredentials): boolean {
private static shouldPromptForUser(credentials: IConnectionInfo): boolean {
return utils.isEmpty(credentials.user) && ConnectionCredentials.isPasswordBasedCredential(credentials);
}
// Prompt for password if this is a password based credential and the password for the profile was empty
// and not explicitly set as empty. If it was explicitly set as empty, only prompt if pw not saved
public static shouldPromptForPassword(credentials: IConnectionCredentials): boolean {
public static shouldPromptForPassword(credentials: IConnectionInfo): boolean {
let isSavedEmptyPassword: boolean = (<IConnectionProfile>credentials).emptyPasswordInput
&& (<IConnectionProfile>credentials).savePassword;
@ -280,7 +281,7 @@ export class ConnectionCredentials implements IConnectionCredentials {
}
public static isPasswordBasedCredential(credentials: IConnectionCredentials): boolean {
public static isPasswordBasedCredential(credentials: IConnectionInfo): boolean {
// TODO consider enum based verification and handling of AD auth here in the future
let authenticationType = credentials.authenticationType;
if (typeof credentials.authenticationType === 'undefined') {

Просмотреть файл

@ -10,6 +10,7 @@ import Interfaces = require('./interfaces');
import { IConnectionProfile } from '../models/interfaces';
import * as ConnectionContracts from '../models/contracts/connection';
import * as Utils from './utils';
import { IConnectionInfo } from 'vscode-mssql';
/**
* Sets sensible defaults for key connection properties, especially
@ -19,7 +20,7 @@ import * as Utils from './utils';
* @param {Interfaces.IConnectionCredentials} connCreds connection to be fixed up
* @returns {Interfaces.IConnectionCredentials} the updated connection
*/
export function fixupConnectionCredentials(connCreds: Interfaces.IConnectionCredentials): Interfaces.IConnectionCredentials {
export function fixupConnectionCredentials(connCreds: IConnectionInfo): IConnectionInfo {
if (!connCreds.server) {
connCreds.server = '';
}
@ -75,7 +76,7 @@ function isAzureDatabase(server: string): boolean {
* @param {Interfaces.CredentialsQuickPickItemType} itemType type of quickpick item to display - this influences the icon shown to the user
* @returns {string} user readable label
*/
export function getPicklistLabel(connCreds: Interfaces.IConnectionCredentials, itemType: Interfaces.CredentialsQuickPickItemType): string {
export function getPicklistLabel(connCreds: IConnectionInfo, itemType: Interfaces.CredentialsQuickPickItemType): string {
let profile: Interfaces.IConnectionProfile = <Interfaces.IConnectionProfile> connCreds;
if (profile.profileName) {
@ -92,7 +93,7 @@ export function getPicklistLabel(connCreds: Interfaces.IConnectionCredentials, i
* @param {Interfaces.IConnectionCredentials} connCreds connection
* @returns {string} description
*/
export function getPicklistDescription(connCreds: Interfaces.IConnectionCredentials): string {
export function getPicklistDescription(connCreds: IConnectionInfo): string {
let desc: string = `[${getConnectionDisplayString(connCreds)}]`;
return desc;
}
@ -104,7 +105,7 @@ export function getPicklistDescription(connCreds: Interfaces.IConnectionCredenti
* @param {Interfaces.IConnectionCredentials} connCreds connection
* @returns {string} details
*/
export function getPicklistDetails(connCreds: Interfaces.IConnectionCredentials): string {
export function getPicklistDetails(connCreds: IConnectionInfo): string {
// In the current spec this is left empty intentionally. Leaving the method as this may change in the future
return undefined;
}
@ -117,7 +118,7 @@ export function getPicklistDetails(connCreds: Interfaces.IConnectionCredentials)
* @param {Interfaces.IConnectionCredentials} conn connection
* @returns {string} display string that can be used in status view or other locations
*/
export function getConnectionDisplayString(creds: Interfaces.IConnectionCredentials): string {
export function getConnectionDisplayString(creds: IConnectionInfo): string {
// Update the connection text
let text: string;
if (creds.connectionString) {
@ -163,7 +164,7 @@ function appendIfNotEmpty(connectionText: string, value: string): string {
* @param {string} [defaultValue] optional default value to use if username is empty and this is not an Integrated auth profile
* @returns {string}
*/
export function getUserNameOrDomainLogin(creds: Interfaces.IConnectionCredentials, defaultValue?: string): string {
export function getUserNameOrDomainLogin(creds: IConnectionInfo, defaultValue?: string): string {
if (!defaultValue) {
defaultValue = '';
}
@ -182,7 +183,7 @@ export function getUserNameOrDomainLogin(creds: Interfaces.IConnectionCredential
* @param {Interfaces.IConnectionCredentials} connCreds connection
* @returns {string} tooltip
*/
export function getTooltip(connCreds: Interfaces.IConnectionCredentials, serverInfo?: ConnectionContracts.ServerInfo): string {
export function getTooltip(connCreds: IConnectionInfo, serverInfo?: ConnectionContracts.ServerInfo): string {
let tooltip: string =
connCreds.connectionString ? 'Connection string: ' + connCreds.connectionString + '\r\n' :
('Server name: ' + connCreds.server + '\r\n' +

Просмотреть файл

@ -11,12 +11,13 @@ import ConnInfo = require('./connectionInfo');
import Utils = require('../models/utils');
import ValidationException from '../utils/validationException';
import { ConnectionCredentials } from '../models/connectionCredentials';
import { IConnectionCredentials, IConnectionProfile, IConnectionCredentialsQuickPickItem, CredentialsQuickPickItemType, AuthenticationTypes } from '../models/interfaces';
import { IConnectionProfile, IConnectionCredentialsQuickPickItem, CredentialsQuickPickItemType, AuthenticationTypes } from '../models/interfaces';
import { ICredentialStore } from '../credentialstore/icredentialstore';
import { CredentialStore } from '../credentialstore/credentialstore';
import { IConnectionConfig } from '../connectionconfig/iconnectionconfig';
import { ConnectionConfig } from '../connectionconfig/connectionconfig';
import VscodeWrapper from '../controllers/vscodeWrapper';
import { IConnectionInfo } from 'vscode-mssql';
/**
* Manages the connections list including saved profiles and the most recently used connections
@ -52,7 +53,7 @@ export class ConnectionStore {
public static get CRED_PROFILE_USER(): string { return CredentialsQuickPickItemType[CredentialsQuickPickItemType.Profile]; }
public static get CRED_MRU_USER(): string { return CredentialsQuickPickItemType[CredentialsQuickPickItemType.Mru]; }
public static formatCredentialIdForCred(creds: IConnectionCredentials, itemType?: CredentialsQuickPickItemType): string {
public static formatCredentialIdForCred(creds: IConnectionInfo, itemType?: CredentialsQuickPickItemType): string {
if (Utils.isEmpty(creds)) {
throw new ValidationException('Missing Connection which is required');
}
@ -162,7 +163,7 @@ export class ConnectionStore {
* Lookup credential store
* @param connectionCredentials Connection credentials of profile for password lookup
*/
public async lookupPassword(connectionCredentials: IConnectionCredentials, isConnectionString: boolean = false): Promise<string> {
public async lookupPassword(connectionCredentials: IConnectionInfo, isConnectionString: boolean = false): Promise<string> {
const credentialId = ConnectionStore.formatCredentialId(
connectionCredentials.server, connectionCredentials.database,
connectionCredentials.user, ConnectionStore.CRED_PROFILE_USER, isConnectionString);
@ -236,10 +237,10 @@ export class ConnectionStore {
* Gets the list of recently used connections. These will not include the password - a separate call to
* {addSavedPassword} is needed to fill that before connecting
*
* @returns {IConnectionCredentials[]} the array of connections, empty if none are found
* @returns {IConnectionInfo[]} the array of connections, empty if none are found
*/
public getRecentlyUsedConnections(): IConnectionCredentials[] {
let configValues = this._context.globalState.get<IConnectionCredentials[]>(Constants.configRecentConnections);
public getRecentlyUsedConnections(): IConnectionInfo[] {
let configValues = this._context.globalState.get<IConnectionInfo[]>(Constants.configRecentConnections);
if (!configValues) {
configValues = [];
}
@ -250,10 +251,10 @@ export class ConnectionStore {
* Adds a connection to the recently used list.
* Password values are stored to a separate credential store if the "savePassword" option is true
*
* @param {IConnectionCredentials} conn the connection to add
* @param {IConnectionInfo} conn the connection to add
* @returns {Promise<void>} a Promise that returns when the connection was saved
*/
public addRecentlyUsed(conn: IConnectionCredentials): Promise<void> {
public addRecentlyUsed(conn: IConnectionInfo): Promise<void> {
const self = this;
return new Promise<void>((resolve, reject) => {
// Get all profiles
@ -264,7 +265,7 @@ export class ConnectionStore {
configValues = configValues.filter(value => !Utils.isSameProfile(<IConnectionProfile>value, <IConnectionProfile>conn));
// Add the connection to the front of the list, taking care to clear out the password field
let savedConn: IConnectionCredentials = Object.assign({}, conn, { password: '' });
let savedConn: IConnectionInfo = Object.assign({}, conn, { password: '' });
configValues.unshift(savedConn);
// Remove last element if needed
@ -341,7 +342,7 @@ export class ConnectionStore {
return this.doSaveCredential(profile, CredentialsQuickPickItemType.Profile, true);
}
private doSaveCredential(conn: IConnectionCredentials, type: CredentialsQuickPickItemType, isConnectionString: boolean = false): Promise<boolean> {
private doSaveCredential(conn: IConnectionInfo, type: CredentialsQuickPickItemType, isConnectionString: boolean = false): Promise<boolean> {
let self = this;
let password = isConnectionString ? conn.connectionString : conn.password;
return new Promise<boolean>((resolve, reject) => {
@ -399,7 +400,7 @@ export class ConnectionStore {
});
}
private createQuickPickItem(item: IConnectionCredentials, itemType: CredentialsQuickPickItemType): IConnectionCredentialsQuickPickItem {
private createQuickPickItem(item: IConnectionInfo, itemType: CredentialsQuickPickItemType): IConnectionCredentialsQuickPickItem {
return <IConnectionCredentialsQuickPickItem> {
label: ConnInfo.getPicklistLabel(item, itemType),
description: ConnInfo.getPicklistDescription(item),
@ -423,7 +424,7 @@ export class ConnectionStore {
/**
* Removes password from a saved profile and credential store
*/
public async removeProfilePassword(connection: IConnectionCredentials): Promise<void> {
public async removeProfilePassword(connection: IConnectionInfo): Promise<void> {
// if the password is saved in the credential store, remove it
let profile = connection as IConnectionProfile;
profile.password = '';
@ -475,7 +476,7 @@ export class ConnectionStore {
return quickPickItems;
}
private getConnectionsFromGlobalState<T extends IConnectionCredentials>(configName: string): T[] {
private getConnectionsFromGlobalState<T extends IConnectionInfo>(configName: string): T[] {
let connections: T[] = [];
// read from the global state
let configValues = this._context.globalState.get<T[]>(configName);
@ -483,7 +484,7 @@ export class ConnectionStore {
return connections;
}
private mapToQuickPickItems(connections: IConnectionCredentials[], itemType: CredentialsQuickPickItemType): IConnectionCredentialsQuickPickItem[] {
private mapToQuickPickItems(connections: IConnectionInfo[], itemType: CredentialsQuickPickItemType): IConnectionCredentialsQuickPickItem[] {
return connections.map(c => this.createQuickPickItem(c, itemType));
}
@ -493,7 +494,7 @@ export class ConnectionStore {
return quickPickItems;
}
private addConnections(connections: IConnectionCredentials[], configValues: IConnectionCredentials[]): void {
private addConnections(connections: IConnectionInfo[], configValues: IConnectionInfo[]): void {
if (configValues) {
for (let index = 0; index < configValues.length; index++) {
let element = configValues[index];

Просмотреть файл

@ -8,6 +8,7 @@ import { AzureAuthType } from 'ads-adal-library';
import vscode = require('vscode');
import { AccountStore } from '../azure/accountStore';
import Constants = require('../constants/constants');
import * as vscodeMssql from 'vscode-mssql';
// interfaces
export enum ContentType {
@ -55,172 +56,9 @@ export const contentTypes = [
Constants.localizedTexts
];
/**
* Interface exposed to the user for creating new database connections.
*/
export interface IConnectionCredentials {
/**
* server name
*/
server: string;
/**
* database name
*/
database: string;
/**
* user name
*/
user: string;
/**
* password
*/
password: string;
/**
* email
*/
email: string;
/**
* accountId
*/
accountId: string;
/**
* The port number to connect to.
*/
port: number;
/**
* Gets or sets the authentication to use.
*/
authenticationType: string;
/**
* Gets or sets the azure account token to use
*/
azureAccountToken: string;
/**
* Gets or sets a Boolean value that indicates whether SQL Server uses SSL encryption for all data sent between the client and server if
* the server has a certificate installed.
*/
encrypt: boolean;
/**
* Gets or sets a value that indicates whether the channel will be encrypted while bypassing walking the certificate chain to validate trust.
*/
trustServerCertificate: boolean;
/**
* Gets or sets a Boolean value that indicates if security-sensitive information, such as the password, is not returned as part of the connection
* if the connection is open or has ever been in an open state.
*/
persistSecurityInfo: boolean;
/**
* Gets or sets the length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error.
*/
connectTimeout: number;
/**
* The number of reconnections attempted after identifying that there was an idle connection failure.
*/
connectRetryCount: number;
/**
* Amount of time (in seconds) between each reconnection attempt after identifying that there was an idle connection failure.
*/
connectRetryInterval: number;
/**
* Gets or sets the name of the application associated with the connection string.
*/
applicationName: string;
/**
* Gets or sets the name of the workstation connecting to SQL Server.
*/
workstationId: string;
/**
* Declares the application workload type when connecting to a database in an SQL Server Availability Group.
*/
applicationIntent: string;
/**
* Gets or sets the SQL Server Language record name.
*/
currentLanguage: string;
/**
* Gets or sets a Boolean value that indicates whether the connection will be pooled or explicitly opened every time that the connection is requested.
*/
pooling: boolean;
/**
* Gets or sets the maximum number of connections allowed in the connection pool for this specific connection string.
*/
maxPoolSize: number;
/**
* Gets or sets the minimum number of connections allowed in the connection pool for this specific connection string.
*/
minPoolSize: number;
/**
* Gets or sets the minimum time, in seconds, for the connection to live in the connection pool before being destroyed.
*/
loadBalanceTimeout: number;
/**
* Gets or sets a Boolean value that indicates whether replication is supported using the connection.
*/
replication: boolean;
/**
* Gets or sets a string that contains the name of the primary data file. This includes the full path name of an attachable database.
*/
attachDbFilename: string;
/**
* Gets or sets the name or address of the partner server to connect to if the primary server is down.
*/
failoverPartner: string;
/**
* If your application is connecting to an AlwaysOn availability group (AG) on different subnets, setting MultiSubnetFailover=true
* provides faster detection of and connection to the (currently) active server.
*/
multiSubnetFailover: boolean;
/**
* When true, an application can maintain multiple active result sets (MARS).
*/
multipleActiveResultSets: boolean;
/**
* Gets or sets the size in bytes of the network packets used to communicate with an instance of SQL Server.
*/
packetSize: number;
/**
* Gets or sets a string value that indicates the type system the application expects.
*/
typeSystemVersion: string;
/**
* Gets or sets the connection string to use for this connection
*/
connectionString: string;
}
// A Connection Profile contains all the properties of connection credentials, with additional
// optional name and details on whether password should be saved
export interface IConnectionProfile extends IConnectionCredentials {
export interface IConnectionProfile extends vscodeMssql.IConnectionInfo {
profileName: string;
savePassword: boolean;
emptyPasswordInput: boolean;
@ -236,7 +74,7 @@ export enum CredentialsQuickPickItemType {
NewConnection
}
export interface IConnectionCredentialsQuickPickItem extends vscode.QuickPickItem {
connectionCreds: IConnectionCredentials;
connectionCreds: vscodeMssql.IConnectionInfo;
quickPickItemType: CredentialsQuickPickItemType;
}

Просмотреть файл

@ -11,11 +11,12 @@ import * as path from 'path';
import * as findRemoveSync from 'find-remove';
import vscode = require('vscode');
import Constants = require('../constants/constants');
import { IAzureSignInQuickPickItem, IConnectionCredentials, IConnectionProfile, AuthenticationTypes } from './interfaces';
import { IAzureSignInQuickPickItem, IConnectionProfile, AuthenticationTypes } from './interfaces';
import { ExtensionContext } from 'vscode';
import LocalizedConstants = require('../constants/localizedConstants');
import fs = require('fs');
import { AzureAuthType } from 'ads-adal-library';
import { IConnectionInfo } from 'vscode-mssql';
// CONSTANTS //////////////////////////////////////////////////////////////////////////////////////
const msInH = 3.6e6;
@ -270,11 +271,11 @@ export function isSameProfile(currentProfile: IConnectionProfile, expectedProfil
* match on all key properties (connectionString or server, db, auth type, user) being identical.
* Other properties are ignored for this purpose
*
* @param {IConnectionCredentials} conn the connection to check
* @param {IConnectionCredentials} expectedConn the connection to try to match
* @param {IConnectionInfo} conn the connection to check
* @param {IConnectionInfo} expectedConn the connection to try to match
* @returns boolean that is true if the connections match
*/
export function isSameConnection(conn: IConnectionCredentials, expectedConn: IConnectionCredentials): boolean {
export function isSameConnection(conn: IConnectionInfo, expectedConn: IConnectionInfo): boolean {
return (conn.connectionString || expectedConn.connectionString) ? conn.connectionString === expectedConn.connectionString :
expectedConn.server === conn.server
&& isSameDatabase(expectedConn.database, conn.database)

Просмотреть файл

@ -7,8 +7,8 @@ import * as vscode from 'vscode';
import ConnectionManager from '../controllers/connectionManager';
import { ObjectExplorerService } from './objectExplorerService';
import { TreeNodeInfo } from './treeNodeInfo';
import { IConnectionCredentials } from '../models/interfaces';
import { Deferred } from '../protocol';
import { IConnectionInfo } from 'vscode-mssql';
export class ObjectExplorerProvider implements vscode.TreeDataProvider<any> {
@ -37,7 +37,7 @@ export class ObjectExplorerProvider implements vscode.TreeDataProvider<any> {
}
}
async createSession(promise: Deferred<TreeNodeInfo>, connectionCredentials?: IConnectionCredentials, context?: vscode.ExtensionContext): Promise<string> {
async createSession(promise: Deferred<TreeNodeInfo>, connectionCredentials?: IConnectionInfo, context?: vscode.ExtensionContext): Promise<string> {
return this._objectExplorerService.createSession(promise, connectionCredentials, context);
}
@ -45,7 +45,7 @@ export class ObjectExplorerProvider implements vscode.TreeDataProvider<any> {
return this._objectExplorerService.expandNode(node, sessionId, promise);
}
public getConnectionCredentials(sessionId: string): IConnectionCredentials {
public getConnectionCredentials(sessionId: string): IConnectionInfo {
if (sessionId) {
return this._objectExplorerService.getConnectionCredentials(sessionId);
}
@ -68,11 +68,11 @@ export class ObjectExplorerProvider implements vscode.TreeDataProvider<any> {
this._objectExplorerService.updateNode(node);
}
public async removeConnectionNodes(connections: IConnectionCredentials[]): Promise<void> {
public async removeConnectionNodes(connections: IConnectionInfo[]): Promise<void> {
await this._objectExplorerService.removeConnectionNodes(connections);
}
public addDisconnectedNode(connectionCredentials: IConnectionCredentials): void {
public addDisconnectedNode(connectionCredentials: IConnectionInfo): void {
this._objectExplorerService.addDisconnectedNode(connectionCredentials);
}
@ -85,7 +85,7 @@ export class ObjectExplorerProvider implements vscode.TreeDataProvider<any> {
return this._objectExplorerExists;
}
public get rootNodeConnections(): IConnectionCredentials[] {
public get rootNodeConnections(): IConnectionInfo[] {
return this._objectExplorerService.rootNodeConnections;
}

Просмотреть файл

@ -13,7 +13,7 @@ import { TreeItemCollapsibleState } from 'vscode';
import { RefreshRequest, RefreshParams } from '../models/contracts/objectExplorer/refreshSessionRequest';
import { CloseSessionRequest, CloseSessionParams } from '../models/contracts/objectExplorer/closeSessionRequest';
import { TreeNodeInfo } from './treeNodeInfo';
import { AuthenticationTypes, IConnectionCredentials, IConnectionProfile } from '../models/interfaces';
import { AuthenticationTypes, IConnectionProfile } from '../models/interfaces';
import LocalizedConstants = require('../constants/localizedConstants');
import { AddConnectionTreeNode } from './addConnectionTreeNode';
import { AccountSignInTreeNode } from './accountSignInTreeNode';
@ -24,8 +24,8 @@ import { ObjectExplorerUtils } from './objectExplorerUtils';
import Utils = require('../models/utils');
import { ConnectionCredentials } from '../models/connectionCredentials';
import { ConnectionProfile } from '../models/connectionProfile';
import { AzureController } from '../azure/azureController';
import providerSettings from '../azure/providerSettings';
import { IConnectionInfo } from 'vscode-mssql';
export class ObjectExplorerService {
@ -34,7 +34,7 @@ export class ObjectExplorerService {
private _treeNodeToChildrenMap: Map<vscode.TreeItem, vscode.TreeItem[]>;
private _nodePathToNodeLabelMap: Map<string, string>;
private _rootTreeNodeArray: Array<TreeNodeInfo>;
private _sessionIdToConnectionCredentialsMap: Map<string, IConnectionCredentials>;
private _sessionIdToConnectionCredentialsMap: Map<string, IConnectionInfo>;
private _expandParamsToTreeNodeInfoMap: Map<ExpandParams, TreeNodeInfo>;
// Deferred promise maps
@ -46,7 +46,7 @@ export class ObjectExplorerService {
this._client = this._connectionManager.client;
this._treeNodeToChildrenMap = new Map<vscode.TreeItem, vscode.TreeItem[]>();
this._rootTreeNodeArray = new Array<TreeNodeInfo>();
this._sessionIdToConnectionCredentialsMap = new Map<string, IConnectionCredentials>();
this._sessionIdToConnectionCredentialsMap = new Map<string, IConnectionInfo>();
this._nodePathToNodeLabelMap = new Map<string, string>();
this._sessionIdToPromiseMap = new Map<string, Deferred<vscode.TreeItem>>();
this._expandParamsToPromiseMap = new Map<ExpandParams, Deferred<TreeNodeInfo[]>>();
@ -379,11 +379,11 @@ export class ObjectExplorerService {
* OE out of
* @param connectionCredentials Connection Credentials for a node
*/
public async createSession(promise: Deferred<vscode.TreeItem | undefined>, connectionCredentials?: IConnectionCredentials,
public async createSession(promise: Deferred<vscode.TreeItem | undefined>, connectionCredentials?: IConnectionInfo,
context?: vscode.ExtensionContext): Promise<string> {
if (!connectionCredentials) {
const connectionUI = this._connectionManager.connectionUI;
connectionCredentials = await connectionUI.showConnections(false);
connectionCredentials = await connectionUI.createAndSaveProfile();
}
if (connectionCredentials) {
// connection string based credential
@ -463,7 +463,7 @@ export class ObjectExplorerService {
}
}
public getConnectionCredentials(sessionId: string): IConnectionCredentials {
public getConnectionCredentials(sessionId: string): IConnectionInfo {
if (this._sessionIdToConnectionCredentialsMap.has(sessionId)) {
return this._sessionIdToConnectionCredentialsMap.get(sessionId);
}
@ -501,7 +501,7 @@ export class ObjectExplorerService {
this.cleanNodeChildren(node);
}
public async removeConnectionNodes(connections: IConnectionCredentials[]): Promise<void> {
public async removeConnectionNodes(connections: IConnectionInfo[]): Promise<void> {
for (let conn of connections) {
for (let node of this._rootTreeNodeArray) {
if (Utils.isSameConnection(node.connectionCredentials, conn)) {
@ -529,7 +529,7 @@ export class ObjectExplorerService {
}
}
public addDisconnectedNode(connectionCredentials: IConnectionCredentials): void {
public addDisconnectedNode(connectionCredentials: IConnectionInfo): void {
const label = (<IConnectionProfile>connectionCredentials).profileName ?
(<IConnectionProfile>connectionCredentials).profileName :
this.createNodeLabel(connectionCredentials);
@ -540,7 +540,7 @@ export class ObjectExplorerService {
this.updateNode(node);
}
private createNodeLabel(credentials: IConnectionCredentials): string {
private createNodeLabel(credentials: IConnectionInfo): string {
let database = credentials.database;
const server = credentials.server;
const authType = credentials.authenticationType;
@ -591,7 +591,7 @@ export class ObjectExplorerService {
return this._rootTreeNodeArray;
}
public get rootNodeConnections(): IConnectionCredentials[] {
public get rootNodeConnections(): IConnectionInfo[] {
const connections = this._rootTreeNodeArray.map(node => node.connectionCredentials);
return connections;
}

Просмотреть файл

@ -6,9 +6,9 @@
import * as vscode from 'vscode';
import { NodeInfo } from '../models/contracts/objectExplorer/nodeInfo';
import { ObjectExplorerUtils } from './objectExplorerUtils';
import { IConnectionCredentials } from '../models/interfaces';
import Constants = require('../constants/constants');
import { ObjectMetadata } from '../models/contracts/metadata/metadataRequest';
import { IConnectionInfo } from 'vscode-mssql';
export class TreeNodeInfo extends vscode.TreeItem {
@ -20,7 +20,7 @@ export class TreeNodeInfo extends vscode.TreeItem {
private _errorMessage: string;
private _sessionId: string;
private _parentNode: TreeNodeInfo;
private _connectionCredentials: IConnectionCredentials;
private _connectionCredentials: IConnectionInfo;
private _metadata: ObjectMetadata;
constructor(
@ -31,7 +31,7 @@ export class TreeNodeInfo extends vscode.TreeItem {
nodeStatus: string,
nodeType: string,
sessionId: string,
connectionCredentials: IConnectionCredentials,
connectionCredentials: IConnectionInfo,
parentNode: TreeNodeInfo,
objectMetadata?: ObjectMetadata
) {
@ -51,7 +51,7 @@ export class TreeNodeInfo extends vscode.TreeItem {
nodeInfo: NodeInfo,
sessionId: string,
parentNode: TreeNodeInfo,
connectionCredentials: IConnectionCredentials,
connectionCredentials: IConnectionInfo,
label?: string,
nodeType?: string): TreeNodeInfo {
let type = nodeType ? nodeType : nodeInfo.nodeType;
@ -97,7 +97,7 @@ export class TreeNodeInfo extends vscode.TreeItem {
return this._parentNode;
}
public get connectionCredentials(): IConnectionCredentials {
public get connectionCredentials(): IConnectionInfo {
return this._connectionCredentials;
}
@ -138,7 +138,7 @@ export class TreeNodeInfo extends vscode.TreeItem {
this._parentNode = value;
}
public set connectionCredentials(value: IConnectionCredentials) {
public set connectionCredentials(value: IConnectionInfo) {
this._connectionCredentials = value;
}
}

Просмотреть файл

@ -3,15 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import vscode = require('vscode');
import Constants = require('../constants/constants');
import * as vscode from 'vscode';
import * as constants from '../constants/constants';
import LocalizedConstants = require('../constants/localizedConstants');
import { ConnectionCredentials } from '../models/connectionCredentials';
import ConnectionManager from '../controllers/connectionManager';
import { ConnectionStore } from '../models/connectionStore';
import { ConnectionProfile } from '../models/connectionProfile';
import { IConnectionCredentials, IConnectionProfile, IConnectionCredentialsQuickPickItem, CredentialsQuickPickItemType } from '../models/interfaces';
import { IConnectionProfile, IConnectionCredentialsQuickPickItem, CredentialsQuickPickItemType } from '../models/interfaces';
import { INameValueChoice, IQuestion, IPrompter, QuestionTypes } from '../prompts/question';
import { Timer } from '../models/utils';
import * as Utils from '../models/utils';
@ -22,8 +21,7 @@ import { AccountStore } from '../azure/accountStore';
import { AzureController } from '../azure/azureController';
import { IAccount } from '../models/contracts/azure/accountInterfaces';
import providerSettings from '../azure/providerSettings';
import { FirewallService } from '../firewall/firewallService';
import { IConnectionInfo } from 'vscode-mssql';
/**
* The different tasks for managing connection profiles.
@ -81,37 +79,24 @@ export class ConnectionUI {
this._errorOutputChannel.show(true);
}
// Helper to let user choose a connection from a picklist
// Return the ConnectionInfo for the user's choice
public showConnections(showExistingConnections: boolean = true): Promise<IConnectionCredentials> {
const self = this;
return new Promise<IConnectionCredentials>((resolve, reject) => {
let picklist: IConnectionCredentialsQuickPickItem[];
if (showExistingConnections) {
picklist = self._connectionStore.getPickListItems();
} else {
picklist = [];
}
if (picklist.length === 0) {
// No connections - go to the create profile workflow
self.createAndSaveProfile().then(resolvedProfile => {
resolve(resolvedProfile);
});
} else {
// We have recent connections - show them in a picklist
self.promptItemChoice({
placeHolder: LocalizedConstants.recentConnectionsPlaceholder,
matchOnDescription: true
}, picklist)
.then(selection => {
if (selection) {
resolve(self.handleSelectedConnection(selection));
} else {
resolve(undefined);
}
});
}
});
/**
* Helper to let user choose a connection from a picklist, or to create a new connection.
* Return the ConnectionInfo for the user's choice
* @returns The connection picked or created.
*/
public async promptForConnection(): Promise<IConnectionInfo | undefined> {
let picklist = this._connectionStore.getPickListItems();
// We have recent connections - show them in a picklist
const selection = await this.promptItemChoice({
placeHolder: LocalizedConstants.recentConnectionsPlaceholder,
matchOnDescription: true
}, picklist);
if (selection) {
return this.handleSelectedConnection(selection);
} else {
return undefined;
}
}
public promptLanguageFlavor(): Promise<string> {
@ -121,12 +106,12 @@ export class ConnectionUI {
{
label: LocalizedConstants.mssqlProviderName,
description: LocalizedConstants.flavorDescriptionMssql,
providerId: Constants.mssqlProviderName
providerId: constants.mssqlProviderName
},
{
label: LocalizedConstants.noneProviderName,
description: LocalizedConstants.flavorDescriptionNone,
providerId: Constants.noneProviderName
providerId: constants.noneProviderName
}
];
self.promptItemChoice({
@ -158,7 +143,7 @@ export class ConnectionUI {
* Helper for waitForLanguageModeToBeSql() method.
*/
private waitForLanguageModeToBeSqlHelper(resolve: any, timer: Timer): void {
if (timer.getDuration() > Constants.timeToWaitForLanguageModeChange) {
if (timer.getDuration() > constants.timeToWaitForLanguageModeChange) {
resolve(false);
} else if (this.vscodeWrapper.isEditingSqlFile) {
resolve(true);
@ -248,13 +233,13 @@ export class ConnectionUI {
// Helper to let the user choose a database on the current server
public showDatabasesOnCurrentServer(
currentCredentials: IConnectionCredentials,
databaseNames: Array<string>): Promise<IConnectionCredentials> {
currentCredentials: IConnectionInfo,
databaseNames: Array<string>): Promise<IConnectionInfo> {
const self = this;
return new Promise<IConnectionCredentials>((resolve, reject) => {
return new Promise<IConnectionInfo>((resolve, reject) => {
const pickListItems: vscode.QuickPickItem[] = databaseNames.map(name => {
let newCredentials: IConnectionCredentials = <any>{};
Object.assign<IConnectionCredentials, IConnectionCredentials>(newCredentials, currentCredentials);
let newCredentials: IConnectionInfo = <any>{};
Object.assign<IConnectionInfo, IConnectionInfo>(newCredentials, currentCredentials);
if (newCredentials['profileName']) {
delete newCredentials['profileName'];
}
@ -311,9 +296,9 @@ export class ConnectionUI {
});
}
public createProfileWithDifferentCredentials(connection: IConnectionCredentials): Promise<IConnectionCredentials> {
public createProfileWithDifferentCredentials(connection: IConnectionInfo): Promise<IConnectionInfo> {
return new Promise<IConnectionCredentials>((resolve, reject) => {
return new Promise<IConnectionInfo>((resolve, reject) => {
this.promptForRetryConnectWithDifferentCredentials().then(result => {
if (result) {
let connectionWithoutCredentials = Object.assign({}, connection, { user: '', password: '', emptyPasswordInput: false });
@ -336,11 +321,11 @@ export class ConnectionUI {
});
}
private handleSelectedConnection(selection: IConnectionCredentialsQuickPickItem): Promise<IConnectionCredentials> {
private handleSelectedConnection(selection: IConnectionCredentialsQuickPickItem): Promise<IConnectionInfo> {
const self = this;
return new Promise<IConnectionCredentials>((resolve, reject) => {
return new Promise<IConnectionInfo>((resolve, reject) => {
if (selection !== undefined) {
let connectFunc: Promise<IConnectionCredentials>;
let connectFunc: Promise<IConnectionInfo>;
if (selection.quickPickItemType === CredentialsQuickPickItemType.NewConnection) {
// call the workflow to create a new connection
connectFunc = self.createAndSaveProfile();
@ -566,7 +551,7 @@ export class ConnectionUI {
placeHolder: startIpAddress,
default: startIpAddress,
validate: (value: string) => {
if (!Number.parseFloat(value) || !value.match(Constants.ipAddressRegex)) {
if (!Number.parseFloat(value) || !value.match(constants.ipAddressRegex)) {
return LocalizedConstants.msgInvalidIpAddress;
}
}
@ -577,7 +562,7 @@ export class ConnectionUI {
message: LocalizedConstants.endIpAddressPrompt,
placeHolder: startIpAddress,
validate: (value: string) => {
if (!Number.parseFloat(value) || !value.match(Constants.ipAddressRegex) ||
if (!Number.parseFloat(value) || !value.match(constants.ipAddressRegex) ||
(Number.parseFloat(value) > Number.parseFloat(startIpAddress))) {
return LocalizedConstants.msgInvalidIpAddress;
}
@ -636,10 +621,10 @@ export class ConnectionUI {
});
}
private fillOrPromptForMissingInfo(selection: IConnectionCredentialsQuickPickItem): Promise<IConnectionCredentials> {
private fillOrPromptForMissingInfo(selection: IConnectionCredentialsQuickPickItem): Promise<IConnectionInfo> {
// If a connection string is present, don't prompt for any other info
if (selection.connectionCreds.connectionString) {
return new Promise<IConnectionCredentials> ((resolve, reject) => {
return new Promise<IConnectionInfo> ((resolve, reject) => {
resolve(selection.connectionCreds);
});
}

Просмотреть файл

@ -8,9 +8,9 @@ import Constants = require('../constants/constants');
import LocalizedConstants = require('../constants/localizedConstants');
import ConnInfo = require('../models/connectionInfo');
import * as ConnectionContracts from '../models/contracts/connection';
import Interfaces = require('../models/interfaces');
import * as Utils from '../models/utils';
import VscodeWrapper from '../controllers/vscodeWrapper';
import { IConnectionInfo } from 'vscode-mssql';
// Status bar element for each file in the editor
class FileStatusBar {
@ -146,7 +146,7 @@ export default class StatusView implements vscode.Disposable {
this.showStatusBarItem(fileUri, bar.statusLanguageFlavor);
}
public connecting(fileUri: string, connCreds: Interfaces.IConnectionCredentials): void {
public connecting(fileUri: string, connCreds: IConnectionInfo): void {
let bar = this.getStatusBar(fileUri);
bar.statusConnection.text = LocalizedConstants.connectingLabel;
bar.statusConnection.command = Constants.cmdDisconnect;
@ -155,7 +155,7 @@ export default class StatusView implements vscode.Disposable {
this.showProgress(fileUri, LocalizedConstants.connectingLabel, bar.statusConnection);
}
public connectSuccess(fileUri: string, connCreds: Interfaces.IConnectionCredentials, serverInfo: ConnectionContracts.ServerInfo): void {
public connectSuccess(fileUri: string, connCreds: IConnectionInfo, serverInfo: ConnectionContracts.ServerInfo): void {
let bar = this.getStatusBar(fileUri);
bar.statusConnection.command = Constants.cmdChooseDatabase;
bar.statusConnection.text = ConnInfo.getConnectionDisplayString(connCreds);
@ -164,7 +164,7 @@ export default class StatusView implements vscode.Disposable {
this.sqlCmdModeChanged(fileUri, false);
}
public connectError(fileUri: string, credentials: Interfaces.IConnectionCredentials, error: ConnectionContracts.ConnectionCompleteParams): void {
public connectError(fileUri: string, credentials: IConnectionInfo, error: ConnectionContracts.ConnectionCompleteParams): void {
let bar = this.getStatusBar(fileUri);
bar.statusConnection.command = Constants.cmdConnect;
bar.statusConnection.text = LocalizedConstants.connectErrorLabel;

Просмотреть файл

@ -16,10 +16,11 @@ import { ConnectionStore } from '../src/models/connectionStore';
import { ConnectionCredentials } from '../src/models/connectionCredentials';
import { IPrompter, IQuestion} from '../src/prompts/question';
import { TestPrompter } from './stubs';
import { IConnectionProfile, IConnectionCredentials } from '../src/models/interfaces';
import { IConnectionProfile } from '../src/models/interfaces';
import VscodeWrapper from '../src/controllers/vscodeWrapper';
import assert = require('assert');
import { IConnectionInfo } from 'vscode-mssql';
suite('ConnectionCredentials Tests', () => {
let defaultProfile: interfaces.IConnectionProfile;
@ -54,7 +55,7 @@ suite('ConnectionCredentials Tests', () => {
});
// ConnectProfile sets up a connection call to ensureRequiredPropertiesSet with the provided profile
function connectProfile( profile: IConnectionProfile, emptyPassword: boolean): Promise<IConnectionCredentials> {
function connectProfile( profile: IConnectionProfile, emptyPassword: boolean): Promise<IConnectionInfo> {
// Setup input paramaters
let isProfile: boolean = true;
let isPasswordRequired: boolean = false;

Просмотреть файл

@ -6,7 +6,7 @@
'use strict';
import vscode = require('vscode');
import * as TypeMoq from 'typemoq';
import { IConnectionCredentials, IConnectionProfile, AuthenticationTypes } from '../src/models/interfaces';
import { IConnectionProfile, AuthenticationTypes } from '../src/models/interfaces';
import { ConnectionCredentials } from '../src/models/connectionCredentials';
import { ConnectionProfile } from '../src/models/connectionProfile';
import { IQuestion, IPrompter, INameValueChoice } from '../src/prompts/question';
@ -15,13 +15,13 @@ import { ConnectionUI } from '../src/views/connectionUI';
import { ConnectionStore } from '../src/models/connectionStore';
import ConnectionManager from '../src/controllers/connectionManager';
import VscodeWrapper from '../src/controllers/vscodeWrapper';
import Constants = require('../src/constants/constants');
import LocalizedConstants = require('../src/constants/localizedConstants');
import assert = require('assert');
import { AccountStore } from '../src/azure/accountStore';
import { IConnectionInfo } from 'vscode-mssql';
function createTestCredentials(): IConnectionCredentials {
const creds: IConnectionCredentials = {
function createTestCredentials(): IConnectionInfo {
const creds: IConnectionInfo = {
server: 'my-server',
database: 'my_db',
user: 'sa',

Просмотреть файл

@ -10,11 +10,12 @@ import VscodeWrapper from '../src/controllers/vscodeWrapper';
import { IPrompter } from '../src/prompts/question';
import { ConnectionStore } from '../src/models/connectionStore';
import ConnectionManager from '../src/controllers/connectionManager';
import { IConnectionProfile, IConnectionCredentials, IConnectionCredentialsQuickPickItem, CredentialsQuickPickItemType } from '../src/models/interfaces';
import { IConnectionCredentialsQuickPickItem, CredentialsQuickPickItemType } from '../src/models/interfaces';
import { ConnectionProfile } from '../src/models/connectionProfile';
import { ConnectionCredentials } from '../src/models/connectionCredentials';
import LocalizedConstants = require('../src/constants/localizedConstants');
import { AccountStore } from '../src/azure/accountStore';
import { IConnectionInfo } from 'vscode-mssql';
suite('Connection UI tests', () => {
@ -68,7 +69,7 @@ suite('Connection UI tests', () => {
let mockConnection = { connectionString: 'test' };
prompter.setup(p => p.promptSingle(TypeMoq.It.isAny())).returns(() => Promise.resolve(item));
prompter.setup(p => p.prompt(TypeMoq.It.isAny(), true)).returns(() => Promise.resolve(mockConnection));
return connectionUI.showConnections(true).then(() => {
return connectionUI.promptForConnection().then(() => {
connectionStore.verify(c => c.getPickListItems(), TypeMoq.Times.once());
prompter.verify(p => p.promptSingle(TypeMoq.It.isAny()), TypeMoq.Times.once());
});
@ -85,7 +86,7 @@ suite('Connection UI tests', () => {
let mockConnection = { connectionString: 'test' };
prompter.setup(p => p.promptSingle(TypeMoq.It.isAny())).returns(() => Promise.resolve(item));
prompter.setup(p => p.prompt(TypeMoq.It.isAny(), true)).returns(() => Promise.resolve(mockConnection));
return connectionUI.showConnections(true).then(() => {
return connectionUI.promptForConnection().then(() => {
connectionStore.verify(c => c.getPickListItems(), TypeMoq.Times.once());
prompter.verify(p => p.promptSingle(TypeMoq.It.isAny()), TypeMoq.Times.once());
});
@ -93,23 +94,12 @@ suite('Connection UI tests', () => {
test('showConnections with recent but no selection', () => {
prompter.setup(p => p.promptSingle(TypeMoq.It.isAny())).returns(() => Promise.resolve(undefined));
return connectionUI.showConnections(true).then(() => {
return connectionUI.promptForConnection().then(() => {
connectionStore.verify(c => c.getPickListItems(), TypeMoq.Times.once());
prompter.verify(p => p.promptSingle(TypeMoq.It.isAny()), TypeMoq.Times.once());
});
});
test('showConnection should not show recent connections if false', () => {
let mockProvider = { providerId: 'test' };
let mockConnection = { connectionString: 'test' };
prompter.setup(p => p.promptSingle(TypeMoq.It.isAny())).returns(() => Promise.resolve(mockProvider));
prompter.setup(p => p.prompt(TypeMoq.It.isAny(), true)).returns(() => Promise.resolve(mockConnection));
return connectionUI.showConnections(false).then(() => {
connectionStore.verify(c => c.getPickListItems(), TypeMoq.Times.never());
prompter.verify(p => p.promptSingle(TypeMoq.It.isAny()), TypeMoq.Times.never());
});
});
test('promptLanguageFlavor should prompt for a language flavor', () => {
let mockProvider = { providerId: 'test' };
prompter.setup(p => p.promptSingle(TypeMoq.It.isAny())).returns(() => Promise.resolve(mockProvider));

Просмотреть файл

@ -11,14 +11,11 @@ import SqlToolsServiceClient from '../src/languageservice/serviceclient';
import { expect, assert } from 'chai';
import { TreeNodeInfo } from '../src/objectExplorer/treeNodeInfo';
import { ConnectionCredentials } from '../src/models/connectionCredentials';
import { Deferred } from '../src/protocol';
import { AddConnectionTreeNode } from '../src/objectExplorer/addConnectionTreeNode';
import * as LocalizedConstants from '../src/constants/localizedConstants';
import { AccountSignInTreeNode } from '../src/objectExplorer/accountSignInTreeNode';
import { ConnectTreeNode } from '../src/objectExplorer/connectTreeNode';
import { NodeInfo } from '../src/models/contracts/objectExplorer/nodeInfo';
import { IConnectionCredentials } from '../src/models/interfaces';
import { Type } from '@angular/core';
suite('Object Explorer Provider Tests', () => {

Просмотреть файл

@ -5,13 +5,13 @@
import assert = require('assert');
import * as TypeMoq from 'typemoq';
import { ExtensionContext, OutputChannel } from 'vscode';
import { OutputChannel } from 'vscode';
import { IPrompter } from '../src/prompts/question';
import SqlToolsServiceClient from './../src/languageservice/serviceclient';
import ConnectionManager from '../src/controllers/connectionManager';
import { IConnectionCredentials, AuthenticationTypes } from '../src/models/interfaces';
import { AuthenticationTypes } from '../src/models/interfaces';
import * as ConnectionContracts from '../src/models/contracts/connection';
import * as LanguageServiceContracts from '../src/models/contracts/languageService';
import MainController from '../src/controllers/mainController';
@ -24,6 +24,7 @@ import VscodeWrapper from '../src/controllers/vscodeWrapper';
import LocalizedConstants = require('../src/constants/localizedConstants');
import { ConnectionUI } from '../src/views/connectionUI';
import Constants = require('../src/constants/constants');
import { IConnectionInfo } from 'vscode-mssql';
function createTestConnectionResult(ownerUri?: string): ConnectionContracts.ConnectionCompleteParams {
let result = new ConnectionContracts.ConnectionCompleteParams();
@ -41,8 +42,8 @@ function createTestFailedConnectionResult(ownerUri?: string, error?: number): Co
return result;
}
function createTestCredentials(): IConnectionCredentials {
const creds: IConnectionCredentials = {
function createTestCredentials(): IConnectionInfo {
const creds: IConnectionInfo = {
server: 'my-server',
database: 'my_db',
user: 'sa',
@ -123,7 +124,7 @@ suite('Per File Connection Tests', () => {
let connectionUIMock = TypeMoq.Mock.ofType(ConnectionUI);
connectionUIMock.setup(x => x.promptToChangeLanguageMode()).returns(x => Promise.resolve(true));
connectionUIMock.setup(x => x.showConnections()).returns(x => Promise.resolve(connectionCreds));
connectionUIMock.setup(x => x.promptForConnection()).returns(x => Promise.resolve(connectionCreds));
// Return undefined to simulate the scenario that user doesn't want to enter new credentials
connectionUIMock.setup(x => x.createProfileWithDifferentCredentials(TypeMoq.It.isAny())).returns(x => Promise.resolve(undefined));
@ -164,7 +165,7 @@ suite('Per File Connection Tests', () => {
let connectionUIMock = TypeMoq.Mock.ofType(ConnectionUI);
connectionUIMock.setup(x => x.promptToChangeLanguageMode()).returns(x => Promise.resolve(true));
connectionUIMock.setup(x => x.showConnections()).returns(x => Promise.resolve(connectionCreds));
connectionUIMock.setup(x => x.promptForConnection()).returns(x => Promise.resolve(connectionCreds));
connectionUIMock.setup(x => x.createProfileWithDifferentCredentials(TypeMoq.It.isAny())).returns(x => Promise.resolve(connectionCreds));
let manager: ConnectionManager = createTestConnectionManager(undefined, vscodeWrapperMock.object, undefined, undefined, connectionUIMock.object);
@ -567,7 +568,7 @@ suite('Per File Connection Tests', () => {
let statusViewMock: TypeMoq.IMock<StatusView> = TypeMoq.Mock.ofType(StatusView);
let actualDbName = undefined;
statusViewMock.setup(x => x.connectSuccess(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.callback((fileUri, creds: IConnectionCredentials, server: ConnectionContracts.ServerInfo) => {
.callback((fileUri, creds: IConnectionInfo, server: ConnectionContracts.ServerInfo) => {
actualDbName = creds.database;
});
@ -586,7 +587,7 @@ suite('Per File Connection Tests', () => {
});
});
function createConnectionResultForCreds(connectionCreds: IConnectionCredentials, dbName?: string): ConnectionContracts.ConnectionCompleteParams {
function createConnectionResultForCreds(connectionCreds: IConnectionInfo, dbName?: string): ConnectionContracts.ConnectionCompleteParams {
let myResult = new ConnectionContracts.ConnectionCompleteParams();
if (!dbName) {
dbName = connectionCreds.database;
@ -625,10 +626,10 @@ suite('Per File Connection Tests', () => {
let statusViewMock: TypeMoq.IMock<StatusView> = TypeMoq.Mock.ofType(StatusView);
statusViewMock.setup(x => x.connectSuccess(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.callback((fileUri, creds: IConnectionCredentials) => { return; });
.callback((fileUri, creds: IConnectionInfo) => { return; });
// And we store any DBs saved to recent connections
let savedConnection: IConnectionCredentials = undefined;
let savedConnection: IConnectionInfo = undefined;
let connectionStoreMock = TypeMoq.Mock.ofType(ConnectionStore);
connectionStoreMock.setup(x => x.addRecentlyUsed(TypeMoq.It.isAny())).returns( conn => {
savedConnection = conn;

170
typings/vscode-mssql.d.ts поставляемый
Просмотреть файл

@ -21,7 +21,177 @@ declare module 'vscode-mssql' {
*/
export interface IExtension {
/**
* Service for accessing DacFx functionality
*/
readonly dacFx: IDacFxService;
/**
* Prompts the user to select an existing connection or create a new one, and then returns the result
*/
promptForConnection(): Promise<IConnectionInfo | undefined>
}
/**
* Information about a database connection
*/
export interface IConnectionInfo {
/**
* server name
*/
server: string;
/**
* database name
*/
database: string;
/**
* user name
*/
user: string;
/**
* password
*/
password: string;
/**
* email
*/
email: string;
/**
* accountId
*/
accountId: string;
/**
* The port number to connect to.
*/
port: number;
/**
* Gets or sets the authentication to use.
*/
authenticationType: string;
/**
* Gets or sets the azure account token to use
*/
azureAccountToken: string;
/**
* Gets or sets a Boolean value that indicates whether SQL Server uses SSL encryption for all data sent between the client and server if
* the server has a certificate installed.
*/
encrypt: boolean;
/**
* Gets or sets a value that indicates whether the channel will be encrypted while bypassing walking the certificate chain to validate trust.
*/
trustServerCertificate: boolean;
/**
* Gets or sets a Boolean value that indicates if security-sensitive information, such as the password, is not returned as part of the connection
* if the connection is open or has ever been in an open state.
*/
persistSecurityInfo: boolean;
/**
* Gets or sets the length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error.
*/
connectTimeout: number;
/**
* The number of reconnections attempted after identifying that there was an idle connection failure.
*/
connectRetryCount: number;
/**
* Amount of time (in seconds) between each reconnection attempt after identifying that there was an idle connection failure.
*/
connectRetryInterval: number;
/**
* Gets or sets the name of the application associated with the connection string.
*/
applicationName: string;
/**
* Gets or sets the name of the workstation connecting to SQL Server.
*/
workstationId: string;
/**
* Declares the application workload type when connecting to a database in an SQL Server Availability Group.
*/
applicationIntent: string;
/**
* Gets or sets the SQL Server Language record name.
*/
currentLanguage: string;
/**
* Gets or sets a Boolean value that indicates whether the connection will be pooled or explicitly opened every time that the connection is requested.
*/
pooling: boolean;
/**
* Gets or sets the maximum number of connections allowed in the connection pool for this specific connection string.
*/
maxPoolSize: number;
/**
* Gets or sets the minimum number of connections allowed in the connection pool for this specific connection string.
*/
minPoolSize: number;
/**
* Gets or sets the minimum time, in seconds, for the connection to live in the connection pool before being destroyed.
*/
loadBalanceTimeout: number;
/**
* Gets or sets a Boolean value that indicates whether replication is supported using the connection.
*/
replication: boolean;
/**
* Gets or sets a string that contains the name of the primary data file. This includes the full path name of an attachable database.
*/
attachDbFilename: string;
/**
* Gets or sets the name or address of the partner server to connect to if the primary server is down.
*/
failoverPartner: string;
/**
* If your application is connecting to an AlwaysOn availability group (AG) on different subnets, setting MultiSubnetFailover=true
* provides faster detection of and connection to the (currently) active server.
*/
multiSubnetFailover: boolean;
/**
* When true, an application can maintain multiple active result sets (MARS).
*/
multipleActiveResultSets: boolean;
/**
* Gets or sets the size in bytes of the network packets used to communicate with an instance of SQL Server.
*/
packetSize: number;
/**
* Gets or sets a string value that indicates the type system the application expects.
*/
typeSystemVersion: string;
/**
* Gets or sets the connection string to use for this connection
*/
connectionString: string;
}
export const enum ExtractTarget {