mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-13 17:22:15 -05:00
Initial LiveShare extension scaffolding (#7170)
* LiveShare initial shared connection * Various cleanups * Fix type * Fix hygiene
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -30,3 +30,4 @@ coverage/
|
||||
test_data/
|
||||
test-results/
|
||||
yarn-error.log
|
||||
*.vsix
|
||||
|
||||
5
extensions/liveshare/.vscodeignore
Normal file
5
extensions/liveshare/.vscodeignore
Normal file
@@ -0,0 +1,5 @@
|
||||
src/**
|
||||
out/**
|
||||
tsconfig.json
|
||||
extension.webpack.config.js
|
||||
yarn.lock
|
||||
30
extensions/liveshare/package.json
Normal file
30
extensions/liveshare/package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "liveshare",
|
||||
"version": "0.1.0",
|
||||
"publisher": "Microsoft",
|
||||
"aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412",
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"engines": {
|
||||
"vscode": "*"
|
||||
},
|
||||
"main": "./out/main",
|
||||
"extensionDependencies": [
|
||||
"vscode.sql"
|
||||
],
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:liveshare"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "12.0.9",
|
||||
"ts-loader": "^5.3.3",
|
||||
"tslint": "^5.12.1",
|
||||
"typescript": "^3.3.1",
|
||||
"vscode": "^1.1.33"
|
||||
},
|
||||
"dependencies": {
|
||||
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.3.0",
|
||||
"vsls": "^0.3.1291"
|
||||
}
|
||||
}
|
||||
37
extensions/liveshare/src/constants.ts
Normal file
37
extensions/liveshare/src/constants.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Provider Constants
|
||||
*/
|
||||
export const LiveShareProviderId: string = 'ads-liveshare';
|
||||
export const LiveShareServiceName: string = 'ads-liveshare';
|
||||
export const VslsSchema: string = 'vsls';
|
||||
|
||||
/**
|
||||
* Connection Provider Constants
|
||||
*/
|
||||
export const connectRequest = 'connect';
|
||||
export const disconnectRequest = 'disconnect';
|
||||
export const cancelConnectRequest = 'cancelConnect';
|
||||
export const changeDatabaseRequest = 'changeDatabase';
|
||||
export const listDatabasesRequest = 'listDatabases';
|
||||
export const getConnectionStringRequest = 'getConnectionString';
|
||||
export const buildConnectionInfoRequest = 'buildConnectionInfo';
|
||||
export const rebuildIntellisenseCacheRequest = 'rebuildIntelliSenseCache';
|
||||
|
||||
/**
|
||||
* Query Provider Constants
|
||||
*/
|
||||
export const cancelQueryRequest = 'cancelQuery';
|
||||
export const runQueryRequest = 'runQuery';
|
||||
export const runQueryStatementRequest = 'runQueryStatement';
|
||||
export const runQueryStringRequest = 'runQueryString';
|
||||
export const runQueryAndReturnRequest = 'runQueryAndReturn';
|
||||
export const parseSyntaxRequest = 'parseSyntax';
|
||||
export const getQueryRowsRequest = 'getQueryRows';
|
||||
export const disposeQueryRequest = 'disposeQuery';
|
||||
export const setQueryExecutionOptionsRequest = 'setQueryExecutionOptions';
|
||||
export const saveResultsRequest = 'saveResultsRequest';
|
||||
77
extensions/liveshare/src/guestSessionManager.ts
Normal file
77
extensions/liveshare/src/guestSessionManager.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import { LiveShare, SharedServiceProxy } from './liveshare';
|
||||
import { LiveShareProviderId, LiveShareServiceName, VslsSchema } from './constants';
|
||||
import { ConnectionProvider } from './providers/connectionProvider';
|
||||
import { StatusProvider, LiveShareDocumentState } from './providers/statusProvider';
|
||||
import { QueryProvider } from './providers/queryProvider';
|
||||
|
||||
declare var require: any;
|
||||
let vsls = require('vsls');
|
||||
|
||||
export class GuestSessionManager {
|
||||
private _statusProvider: StatusProvider;
|
||||
|
||||
constructor(
|
||||
context: vscode.ExtensionContext,
|
||||
vslsApi: LiveShare
|
||||
) {
|
||||
let self = this;
|
||||
vscode.workspace.onDidOpenTextDocument(params => this.onDidOpenTextDocument(params));
|
||||
|
||||
vslsApi!.onDidChangeSession(async function onLiveShareSessionCHange(e: any) {
|
||||
const isHost = e.session.role === vsls.Role.Host;
|
||||
if (!e.session.id && isHost) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sharedServiceProxy: SharedServiceProxy = await vslsApi.getSharedService(LiveShareServiceName);
|
||||
if (!sharedServiceProxy) {
|
||||
vscode.window.showErrorMessage('Could not access a shared service. You have to set "liveshare.features" to "experimental" in your user settings in order to use this extension.');
|
||||
return;
|
||||
}
|
||||
|
||||
const connectionProvider = new ConnectionProvider(isHost, vslsApi, sharedServiceProxy);
|
||||
|
||||
const queryProvider = new QueryProvider(false);
|
||||
queryProvider.initialize(false, sharedServiceProxy);
|
||||
|
||||
self._statusProvider = new StatusProvider(
|
||||
isHost,
|
||||
vslsApi,
|
||||
connectionProvider,
|
||||
sharedServiceProxy);
|
||||
});
|
||||
}
|
||||
|
||||
private async onDidOpenTextDocument(doc: vscode.TextDocument): Promise<void> {
|
||||
if (this._statusProvider && this.isLiveShareDocument(doc)) {
|
||||
let documentState: LiveShareDocumentState = await this._statusProvider.getDocumentState(doc);
|
||||
if (documentState) {
|
||||
let queryDocument = await azdata.queryeditor.getQueryDocument(doc.uri.toString());
|
||||
if (queryDocument) {
|
||||
let connectionOptions: Map<string, any> = new Map<string, any>();
|
||||
connectionOptions['providerName'] = LiveShareProviderId;
|
||||
connectionOptions['serverName'] = documentState.serverName;
|
||||
connectionOptions['databaseName'] = documentState.databaseName;
|
||||
connectionOptions['userName'] = 'liveshare';
|
||||
connectionOptions['password'] = 'liveshare';
|
||||
connectionOptions['authenticationType'] = 'liveshare';
|
||||
connectionOptions['savePassword'] = false;
|
||||
connectionOptions['saveProfile'] = false;
|
||||
let profile = azdata.connection.ConnectionProfile.createFrom(connectionOptions);
|
||||
queryDocument.connect(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private isLiveShareDocument(doc: vscode.TextDocument): boolean {
|
||||
return doc && doc.uri.scheme === VslsSchema;
|
||||
}
|
||||
}
|
||||
47
extensions/liveshare/src/hostSessionManager.ts
Normal file
47
extensions/liveshare/src/hostSessionManager.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { LiveShare, SharedService } from './liveshare';
|
||||
import { ConnectionProvider } from './providers/connectionProvider';
|
||||
import { QueryProvider } from './providers/queryProvider';
|
||||
import { StatusProvider } from './providers/statusProvider';
|
||||
import { LiveShareServiceName } from './constants';
|
||||
|
||||
declare var require: any;
|
||||
let vsls = require('vsls');
|
||||
|
||||
export class HostSessionManager {
|
||||
constructor(
|
||||
context: vscode.ExtensionContext,
|
||||
vslsApi: LiveShare
|
||||
) {
|
||||
vslsApi!.onDidChangeSession(async function onLiveShareSessionCHange(e: any) {
|
||||
const isHost = e.session.role === vsls.Role.Host;
|
||||
if (!isHost) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sharedService: SharedService = await vslsApi.shareService(LiveShareServiceName);
|
||||
if (!sharedService) {
|
||||
vscode.window.showErrorMessage('Could not create a shared service. You have to set "liveshare.features" to "experimental" in your user settings in order to use this extension.');
|
||||
return;
|
||||
}
|
||||
|
||||
const connectionProvider = new ConnectionProvider(isHost, vslsApi, sharedService);
|
||||
|
||||
const queryProvider = new QueryProvider(true);
|
||||
queryProvider.initialize(true, sharedService);
|
||||
|
||||
/* tslint:disable:no-unused-expression */
|
||||
new StatusProvider(
|
||||
isHost,
|
||||
vslsApi,
|
||||
connectionProvider,
|
||||
sharedService);
|
||||
/* tslint:enable:no-unused-expression */
|
||||
});
|
||||
}
|
||||
}
|
||||
559
extensions/liveshare/src/liveshare.ts
Normal file
559
extensions/liveshare/src/liveshare.ts
Normal file
@@ -0,0 +1,559 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Entrypoint and type definitions for Live Share for VS Code extension API
|
||||
*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
/**
|
||||
* Root API that is used to acquire access to the main Live Share API.
|
||||
*
|
||||
* An implementation of this interface is returned by the Live Share extension's
|
||||
* activation function. Ordinarily this interface is not used directly; use the
|
||||
* `getApiAsync()` helper function above instead.
|
||||
*/
|
||||
export interface LiveShareExtension {
|
||||
/**
|
||||
* Requests a specific version of the Live Share API for use by another extension.
|
||||
*
|
||||
* @returns a promise that resolves to the requested API, or `null` if the requested
|
||||
* API is not available
|
||||
*/
|
||||
getApi(requestedApiVersion: string): Promise<LiveShare | null>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward definition of the ContactServiceProvider interface
|
||||
*/
|
||||
export interface ContactServiceProvider {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Main API that enables other VS Code extensions to access Live Share capabilities.
|
||||
*/
|
||||
export interface LiveShare {
|
||||
/**
|
||||
* Status of participation in a sharing session, if any.
|
||||
* Also includes the Live Share user info, if signed in.
|
||||
*/
|
||||
readonly session: Session;
|
||||
|
||||
/**
|
||||
* Event that notifies listeners when participation in a sharing session
|
||||
* starts or stops.
|
||||
*/
|
||||
readonly onDidChangeSession: vscode.Event<SessionChangeEvent>;
|
||||
|
||||
/** List of peers connected to the current sharing session, NOT including oneself. */
|
||||
readonly peers: Peer[];
|
||||
|
||||
/** Event that notifies listeners when peers join or leave the session. */
|
||||
readonly onDidChangePeers: vscode.Event<PeersChangeEvent>;
|
||||
|
||||
/**
|
||||
* Starts a new session, sharing the currenly opened workspace.
|
||||
* Or if sharing was already started, retrieves the join link.
|
||||
*
|
||||
* Not valid when joined to a session as a guest.
|
||||
*
|
||||
* @returns Join link for the new or existing session, or `null` if sharing failed.
|
||||
*/
|
||||
share(options?: ShareOptions): Promise<vscode.Uri | null>;
|
||||
|
||||
/**
|
||||
* Joins a shared session using a link acquired from the host.
|
||||
*
|
||||
* Note joining another session requires either reloading the current window
|
||||
* (and all extensions) or opening a new window.
|
||||
*
|
||||
* @param link Join link for a shared session.
|
||||
*/
|
||||
join(link: vscode.Uri, options?: JoinOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* When called as a Host, ends the current sharing session and disconnects all guests,
|
||||
* (without reloading the window or extensions).
|
||||
*
|
||||
* When called as a Guest, disconnects from the current sharing session
|
||||
* and closes the workspace (causing extensions to be reloaded).
|
||||
*/
|
||||
end(): Promise<void>;
|
||||
|
||||
/**
|
||||
* Provides a named service to guests. The service is made available only
|
||||
* while a Live Share session is active in the Host role.
|
||||
*
|
||||
* The caller must add request and/or notification handlers to the returned
|
||||
* `SharedService` instance in order to receive messages from guests.
|
||||
*
|
||||
* A `SharedService` instance is returned even if the service is not
|
||||
* currently made available because there is no hosted sharing session.
|
||||
* The service will be automatically made available when a hosted sharing
|
||||
* session begins.
|
||||
*
|
||||
* NOTE: Access to shared services may be restricted.
|
||||
* If the caller is not permitted, this method returns `null`.
|
||||
*/
|
||||
shareService(name: string): Promise<SharedService | null>;
|
||||
|
||||
/**
|
||||
* Stops providing a named service to guests.
|
||||
*
|
||||
* NOTE: Access to shared services may be restricted.
|
||||
*/
|
||||
unshareService(name: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Gets a proxy for a named service provided by a Host. The service is
|
||||
* available only while a Live Share session is active in the Guest role
|
||||
* AND the session Host has shared the named service.
|
||||
*
|
||||
* The caller must add a notification handler to the returned `SharedService`
|
||||
* instance in order to receive notifications from hosts. (Service proxies
|
||||
* cannot receive requests, only send them.)
|
||||
*
|
||||
* A `SharedServiceProxy` instance is returned even if the service is not
|
||||
* currently available (either because there is no active sharing session or
|
||||
* because the Host has not shared the service). Listen to the event on the
|
||||
* instance to be notified when the service becomes available or unavailable.
|
||||
*
|
||||
* NOTE: Access to shared services may be restricted.
|
||||
* If the caller is not permitted, this method returns `null`.
|
||||
*/
|
||||
getSharedService(name: string): Promise<SharedServiceProxy | null>;
|
||||
|
||||
/**
|
||||
* Converts a local `file:` URI to a `vsls:` URI. Only available in host role.
|
||||
*/
|
||||
convertLocalUriToShared(localUri: vscode.Uri): vscode.Uri;
|
||||
|
||||
/**
|
||||
* Converts a `vsls:` URI to a local `file:` URI. Only available in host role.
|
||||
*/
|
||||
convertSharedUriToLocal(sharedUri: vscode.Uri): vscode.Uri;
|
||||
|
||||
/**
|
||||
* Registers a command to be added to the Live Share contextual command palette.
|
||||
*
|
||||
* @param command command identifier, as declared in the calling extension's manifest
|
||||
* @param isEnabled optional callback to check if the command is available
|
||||
* @param thisArg optional `this` for the callback
|
||||
* @returns Disposable that can be used to unregister the command, or null if the command
|
||||
* could not be registered.
|
||||
*
|
||||
* The command must be declared in the `contributes.commands` section of the calling
|
||||
* extension manifest, including extended VSLS label and detail properties, for example:
|
||||
* "contributes": {
|
||||
* "commands": [
|
||||
* {
|
||||
* "command": "myextension.mycommand",
|
||||
* "title": "Live Share: Do Something",
|
||||
* "vsls-label": "$(star) Do Something",
|
||||
* "vsls-detail": "Do some VSLS-related command provided by this extension"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* Extensions should use this capability judiciously, to avoid cluttering the Live Share
|
||||
* command palette. If contributing a group of related commands, put them in a separate
|
||||
* quick-pick menu that is brought up by a single command registered here.
|
||||
*
|
||||
* NOTE: Ability to contribute commands to the Live Share command palette may be restricted.
|
||||
* If the caller is not permitted, this method returns `null`.
|
||||
*/
|
||||
registerCommand(
|
||||
command: string,
|
||||
isEnabled?: () => boolean,
|
||||
thisArg?: any): vscode.Disposable | null;
|
||||
|
||||
/**
|
||||
* Registers a provider that can extend a Live Share tree view by providing additional items.
|
||||
*
|
||||
* @param viewId One of the Live Share tree view IDs. Not all Live Share tree views support
|
||||
* data providers; currently only the session and session explorer views do.
|
||||
* @param treeDataProvider A provider that provides additional data for the Live Share view.
|
||||
* @returns Disposable that can be used to unregister the provider, or null if the provider
|
||||
* could not be registered.
|
||||
*
|
||||
* NOTE: Ability to contribute commands to Live Share tree views may be restricted. If the
|
||||
* caller is not permitted, this method returns `null`.
|
||||
*/
|
||||
registerTreeDataProvider<T>(
|
||||
viewId: View,
|
||||
treeDataProvider: vscode.TreeDataProvider<T>,
|
||||
): vscode.Disposable | null;
|
||||
|
||||
/**
|
||||
* Registers a contact service provider.
|
||||
*
|
||||
* @param name Name of the provider ('skype', 'teams',..)
|
||||
* @param contactServiceProvider implementation of the ContactServiceProvider interface
|
||||
* @returns Disposable that can be used to unregister the provider, or null if the provider
|
||||
* could not be registered.
|
||||
*/
|
||||
registerContactServiceProvider(
|
||||
name: string,
|
||||
contactServiceProvider: ContactServiceProvider,
|
||||
): vscode.Disposable | null;
|
||||
|
||||
/**
|
||||
* Sends a request to share a local server in the active collaboration session.
|
||||
*
|
||||
* @param server Contains properties pertaining to the local server.
|
||||
* @returns A registration object that will un-share the server when disposed.
|
||||
*/
|
||||
shareServer(server: Server): Promise<vscode.Disposable>;
|
||||
|
||||
/**
|
||||
* Request contacts to our presence providers
|
||||
* @param emails Request contacts emails
|
||||
*/
|
||||
getContacts(emails: string[]): Promise<ContactsCollection>;
|
||||
}
|
||||
|
||||
export interface ShareOptions {
|
||||
/**
|
||||
* Suppress display of the usual notification that indicates that sharing
|
||||
* started. Also suppresses copying the join link to the clipboard. When
|
||||
* setting this option, the caller should take care of showing or
|
||||
* communicating the link somehow.
|
||||
*/
|
||||
suppressNotification?: boolean;
|
||||
|
||||
/**
|
||||
* (NOT IMPLEMENTED) Default access level for incoming guests. The host may
|
||||
* override this setting on a per-guest basis.
|
||||
*/
|
||||
access?: Access;
|
||||
}
|
||||
|
||||
export interface JoinOptions {
|
||||
/**
|
||||
* Open the joined workspace in a new window, instead of re-using the current window.
|
||||
*/
|
||||
newWindow?: boolean;
|
||||
correlationId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a local TCP server listening on the given port.
|
||||
*/
|
||||
export interface Server {
|
||||
/**
|
||||
* Local TCP port the server is listening on.
|
||||
*/
|
||||
port: number;
|
||||
/**
|
||||
* User-friendly name of the server.
|
||||
*/
|
||||
displayName?: string;
|
||||
/**
|
||||
* Default URL users will be redirected to when accessing the server.
|
||||
*/
|
||||
browseUrl?: string;
|
||||
}
|
||||
|
||||
export enum Role {
|
||||
None = 0,
|
||||
Host = 1,
|
||||
Guest = 2,
|
||||
}
|
||||
|
||||
/** This is just a placeholder for a richer access control model to be added later. */
|
||||
export enum Access {
|
||||
None = 0,
|
||||
ReadOnly = 1,
|
||||
ReadWrite = 3,
|
||||
Owner = 0xFF,
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticated Live Share user information.
|
||||
*
|
||||
* NOTE: Access to user information may be restricted.
|
||||
* If the caller is not permitted, the `Peer.user` property returns 'null'.
|
||||
*/
|
||||
export interface UserInfo {
|
||||
/**
|
||||
* User display name.
|
||||
*/
|
||||
readonly displayName: string;
|
||||
|
||||
/**
|
||||
* Validated email address.
|
||||
*/
|
||||
readonly emailAddress: string | null;
|
||||
|
||||
/**
|
||||
* The username that the provider (e.g. GitHub) makes available.
|
||||
*/
|
||||
readonly userName: string | null;
|
||||
|
||||
/**
|
||||
* User id. This is persistent ID that stays the same for the same user
|
||||
* if the user re-joins the session and even between sessions for some time.
|
||||
*/
|
||||
readonly id: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents one participant in a sharing session.
|
||||
*/
|
||||
export interface Peer {
|
||||
/** Integer that uniquely identifies a peer within the scope of a session. */
|
||||
readonly peerNumber: number;
|
||||
|
||||
/**
|
||||
* Authenticated Live Share user information.
|
||||
*
|
||||
* NOTE: Access to user information may be restricted.
|
||||
* If the caller is not permitted, this property returns 'null'.
|
||||
*/
|
||||
readonly user: UserInfo | null;
|
||||
|
||||
/**
|
||||
* Role within the session. Each session has exactly one host; the rest of
|
||||
* the peers are guests.
|
||||
*/
|
||||
readonly role: Role;
|
||||
|
||||
/**
|
||||
* Access level within the session. The host has full "owner" access to the
|
||||
* session. Guests may have their access limited by the host.
|
||||
*/
|
||||
readonly access: Access;
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about the current session, including user information (in the base class).
|
||||
*/
|
||||
export interface Session extends Peer {
|
||||
/**
|
||||
* Globally unique identifier for the current session, or null if there is no active session.
|
||||
*/
|
||||
readonly id: string | null;
|
||||
}
|
||||
|
||||
export interface SessionChangeEvent {
|
||||
readonly session: Session;
|
||||
}
|
||||
|
||||
export interface PeersChangeEvent {
|
||||
readonly added: Peer[];
|
||||
readonly removed: Peer[];
|
||||
}
|
||||
|
||||
export interface RequestHandler {
|
||||
(args: any[], cancellation: vscode.CancellationToken): any | Promise<any>;
|
||||
}
|
||||
|
||||
export interface NotifyHandler {
|
||||
(args: object): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A service that is provided by the host for use by guests.
|
||||
*/
|
||||
export interface SharedService {
|
||||
/** A shared service is available when a sharing session is active as a Host. */
|
||||
readonly isServiceAvailable: boolean;
|
||||
readonly onDidChangeIsServiceAvailable: vscode.Event<boolean>;
|
||||
|
||||
/**
|
||||
* Registers a callback to be invoked when a request is sent to the service.
|
||||
*
|
||||
* @param name Request method name
|
||||
*/
|
||||
onRequest(name: string, handler: RequestHandler): void;
|
||||
|
||||
/**
|
||||
* Registers a callback to be invoked when a notification is sent to the service.
|
||||
*
|
||||
* @param name Notify event name
|
||||
*/
|
||||
onNotify(name: string, handler: NotifyHandler): void;
|
||||
|
||||
/**
|
||||
* Sends a notification (event) from the service. Does not wait for a response.
|
||||
*
|
||||
* If no sharing session is active, this method does nothing.
|
||||
*
|
||||
* @param name notify event name
|
||||
* @param args notify event args object
|
||||
*/
|
||||
notify(name: string, args: object): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A proxy that allows guests to access a host-provided service.
|
||||
*/
|
||||
export interface SharedServiceProxy {
|
||||
/**
|
||||
* A shared service proxy is available when a sharing session is active as a
|
||||
* Guest, and the Host has shared a service with the same name.
|
||||
*/
|
||||
readonly isServiceAvailable: boolean;
|
||||
readonly onDidChangeIsServiceAvailable: vscode.Event<boolean>;
|
||||
|
||||
/**
|
||||
* Registers a callback to be invoked when a notification is sent by the service.
|
||||
*
|
||||
* @param name notify event name
|
||||
*/
|
||||
onNotify(name: string, handler: NotifyHandler): void;
|
||||
|
||||
/**
|
||||
* Sends a request (method call) to the service and waits for a response.
|
||||
*
|
||||
* @param name request method name
|
||||
*
|
||||
* @returns a promise that waits asynchronously for a response
|
||||
*
|
||||
* @throws SharedServiceProxyError if the service is not currently available
|
||||
* (because there is no active sharing session or no peer has provided the service)
|
||||
*
|
||||
* @throws SharedServiceResponseError (via rejected promise) if the service's
|
||||
* request handler throws an error
|
||||
*/
|
||||
request(name: string, args: any[], cancellation?: vscode.CancellationToken): Promise<any>;
|
||||
|
||||
/**
|
||||
* Sends a notification (event) to the service. (Does not wait for a response.)
|
||||
*
|
||||
* If the service is not currently available (either because there is
|
||||
* no active sharing session or because no peer has provided the service)
|
||||
* then this method does nothing.
|
||||
*
|
||||
* @param name notify event name
|
||||
* @param args notify event args object
|
||||
*/
|
||||
notify(name: string, args: object): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error thrown by a proxy when a request to a shared service cannot be made
|
||||
* because the service is not available or cannot be reached.
|
||||
*/
|
||||
export interface SharedServiceProxyError extends Error {
|
||||
}
|
||||
|
||||
/**
|
||||
* Error thrown by a proxy when a shared service's request handler threw an error.
|
||||
* The remote message and remote stack are propagated back to the proxy.
|
||||
*/
|
||||
export interface SharedServiceResponseError extends Error {
|
||||
remoteStack?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifiers for Live Share tree views. These identifiers may be used by other extensions
|
||||
* to extend Live Share tree views with additional nodes via the `registerTreeDataProvider()`
|
||||
* API.
|
||||
*/
|
||||
export enum View {
|
||||
Session = 'liveshare.session',
|
||||
ExplorerSession = 'liveshare.session.explorer',
|
||||
Contacts = 'liveshare.contacts',
|
||||
Help = 'liveshare.help',
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifiers for Live Share tree view items. These identifiers may be used by other
|
||||
* extensions to extend Live Share tree items with additional commands using conditional
|
||||
* expressions in the `view/item/context` section of their own package.json.
|
||||
*/
|
||||
export enum ViewItem {
|
||||
// session item groups
|
||||
Participants = 'participants',
|
||||
Servers = 'servers',
|
||||
Terminals = 'terminals',
|
||||
|
||||
// participants
|
||||
CurrentUser = 'participants.currentuser', // (not currently shown)
|
||||
Guest = 'participants.guest',
|
||||
FollowedGuest = 'participants.guest.followed',
|
||||
Participant = 'participants.participant',
|
||||
FollowedParticipant = 'participants.participant.followed',
|
||||
|
||||
GuestAnonymous = 'participants.guest.anonymous',
|
||||
FollowedGuestAnonymous = 'participants.guest.followed.anonymous',
|
||||
|
||||
GuestElevated = 'participants.guest.elevated',
|
||||
FollowedGuestElevated = 'participants.guest.followed.elevated',
|
||||
|
||||
// servers
|
||||
LocalServer = 'servers.local',
|
||||
RemoteServer = 'servers.remote',
|
||||
|
||||
// terminals
|
||||
LocalTerminalReadOnly = 'terminals.local.readonly',
|
||||
LocalTerminalReadWrite = 'terminals.local.readwrite',
|
||||
RemoteTerminal = 'terminals.remote',
|
||||
|
||||
// contacts
|
||||
SuggestedContacts = 'contacts.suggested',
|
||||
AvailableContacts = 'contacts.available',
|
||||
ContactsProvider = 'contacts.provider',
|
||||
SelfContact = 'contacts.selfContact',
|
||||
Contact = 'contacts.contact',
|
||||
ContactOffline = 'contacts.contact.offline',
|
||||
RecentContact = 'contacts.recentContact',
|
||||
RecentContactOffline = 'contacts.recentContact.offline',
|
||||
NoContact = 'contacts.noContact',
|
||||
RecentContacts = 'contacts.RecentContacts',
|
||||
NoSuggestedContacts = 'contacts.NoSuggestedUsers',
|
||||
NoRecentContacts = 'contacts.NoRecentContacts',
|
||||
InvitedContact = 'contacts.invited',
|
||||
|
||||
// help
|
||||
SessionFeedbackQuestion = 'help.sessionFeedback',
|
||||
ReportAProblem = 'help.reportAProblem',
|
||||
TweetUsYourFeedback = 'help.tweetUsYourFeedback',
|
||||
Survey = 'help.survey',
|
||||
GoodFeedback = 'help.goodFeedback',
|
||||
BadFeedback = 'help.badFeedback',
|
||||
DontAskAgain = 'help.dontAskAgain',
|
||||
Thankyou = 'help.thankyou',
|
||||
MoreInfo = 'help.moreinfo',
|
||||
|
||||
// Shown while session sharing / joining is in progress
|
||||
Loading = 'loading',
|
||||
|
||||
// Other / unspecified item type
|
||||
Other = 'other',
|
||||
}
|
||||
|
||||
export interface InviteContactOptions {
|
||||
|
||||
/**
|
||||
* This option will force the invite to only use the email channel
|
||||
*/
|
||||
useEmail?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represent a contact with live presence support
|
||||
*/
|
||||
export interface Contact {
|
||||
readonly onDidChange: vscode.Event<string[]>;
|
||||
readonly id: string;
|
||||
readonly email: string;
|
||||
readonly displayName?: string;
|
||||
readonly status?: string;
|
||||
readonly avatarUri?: string;
|
||||
|
||||
invite(options?: InviteContactOptions): Promise<boolean>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represent a collection of contacts that can be disposed at once
|
||||
*/
|
||||
export interface ContactsCollection {
|
||||
readonly contacts: { [email: string]: Contact };
|
||||
dispose(): Promise<void>;
|
||||
}
|
||||
26
extensions/liveshare/src/main.ts
Normal file
26
extensions/liveshare/src/main.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { GuestSessionManager } from './guestSessionManager';
|
||||
import { HostSessionManager } from './hostSessionManager';
|
||||
|
||||
declare var require: any;
|
||||
let vsls = require('vsls');
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
const vslsApi = await vsls.getApi();
|
||||
if (!vslsApi) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* tslint:disable:no-unused-expression */
|
||||
new HostSessionManager(context, vslsApi);
|
||||
new GuestSessionManager(context, vslsApi);
|
||||
/* tslint:enable:no-unused-expression */
|
||||
}
|
||||
|
||||
export function deactivate(): void {
|
||||
}
|
||||
215
extensions/liveshare/src/providers/connectionProvider.ts
Normal file
215
extensions/liveshare/src/providers/connectionProvider.ts
Normal file
@@ -0,0 +1,215 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as constants from '../constants';
|
||||
|
||||
import { LiveShare, SharedService, SharedServiceProxy } from '../liveshare';
|
||||
|
||||
export class ConnectionProvider {
|
||||
private _sharedService: SharedService;
|
||||
private _sharedServiceProxy: SharedServiceProxy;
|
||||
|
||||
protected _onConnect: vscode.EventEmitter<any> = new vscode.EventEmitter<any>();
|
||||
public readonly onConnect: vscode.Event<any> = this._onConnect.event;
|
||||
|
||||
protected _onDisconnect: vscode.EventEmitter<any> = new vscode.EventEmitter<any>();
|
||||
public readonly onDisconnect: vscode.Event<any> = this._onDisconnect.event;
|
||||
|
||||
protected _onConnectionChanged: vscode.EventEmitter<any> = new vscode.EventEmitter<any>();
|
||||
public readonly onConnectionChanged: vscode.Event<any> = this._onConnectionChanged.event;
|
||||
|
||||
private _onConnectionCompleteHandler: (connSummary: azdata.ConnectionInfoSummary) => any;
|
||||
|
||||
public constructor(
|
||||
private _isHost: boolean,
|
||||
private _vslsApi: LiveShare,
|
||||
service: SharedService | SharedServiceProxy) {
|
||||
if (this._isHost) {
|
||||
this._sharedService = <SharedService>service;
|
||||
this.registerProviderListener();
|
||||
} else {
|
||||
this._sharedServiceProxy = <SharedServiceProxy>service;
|
||||
this.registerProvider();
|
||||
}
|
||||
}
|
||||
|
||||
public registerProviderListener(): void {
|
||||
let self = this;
|
||||
azdata.connection.registerConnectionEventListener({
|
||||
onConnectionEvent(type: azdata.connection.ConnectionEventType, ownerUri: string, profile: azdata.IConnectionProfile) {
|
||||
try {
|
||||
let localUri: vscode.Uri = self._vslsApi.convertLocalUriToShared(vscode.Uri.parse(ownerUri));
|
||||
ownerUri = localUri.toString();
|
||||
} catch {
|
||||
}
|
||||
|
||||
self._sharedService.notify(<string>type, {
|
||||
ownerUri: ownerUri,
|
||||
profile: profile
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.connectRequest, (args: any) => {
|
||||
return;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.disconnectRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.cancelConnectRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.changeDatabaseRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.listDatabasesRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
this._sharedService.onRequest(constants.getConnectionStringRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.buildConnectionInfoRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.rebuildIntellisenseCacheRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public registerProvider(): vscode.Disposable {
|
||||
const self = this;
|
||||
this._sharedServiceProxy.onNotify('onConnect', (args: any) => {
|
||||
this._onConnect.fire(args);
|
||||
return args;
|
||||
});
|
||||
|
||||
this._sharedServiceProxy.onNotify('onDisconnect', (args: any) => {
|
||||
this._onDisconnect.fire(args);
|
||||
return args;
|
||||
});
|
||||
|
||||
this._sharedServiceProxy.onNotify('onConnectionChanged', (args: any) => {
|
||||
this._onConnectionChanged.fire(args);
|
||||
return args;
|
||||
});
|
||||
|
||||
let connect = (ownerUri: string, connInfo: azdata.ConnectionInfo): Thenable<boolean> => {
|
||||
if (self._onConnectionCompleteHandler) {
|
||||
// "test" liveshare connection details to be filled out in later iteration
|
||||
let connSummary: azdata.ConnectionInfoSummary = {
|
||||
ownerUri: ownerUri,
|
||||
connectionId: ownerUri,
|
||||
messages: undefined,
|
||||
errorMessage: undefined,
|
||||
errorNumber: undefined,
|
||||
connectionSummary: {
|
||||
serverName: connInfo.options['serverName'],
|
||||
databaseName: connInfo.options['databaseName'],
|
||||
userName: 'liveshare'
|
||||
},
|
||||
serverInfo: {
|
||||
serverMajorVersion: 1,
|
||||
serverMinorVersion: 0,
|
||||
serverReleaseVersion: 1,
|
||||
engineEditionId: 1,
|
||||
serverVersion: '1.0',
|
||||
serverLevel: '1',
|
||||
serverEdition: '1',
|
||||
isCloud: false,
|
||||
azureVersion: 1,
|
||||
osVersion: '1',
|
||||
options: connInfo.options
|
||||
}
|
||||
};
|
||||
self._onConnectionCompleteHandler(connSummary);
|
||||
}
|
||||
|
||||
return self._sharedServiceProxy.request(constants.connectRequest, [{
|
||||
ownerUri: ownerUri,
|
||||
connInfo: connInfo
|
||||
}]);
|
||||
};
|
||||
|
||||
let disconnect = (ownerUri: string): Thenable<boolean> => {
|
||||
return self._sharedServiceProxy.request(constants.disconnectRequest, [{
|
||||
ownerUri: ownerUri
|
||||
}]);
|
||||
};
|
||||
|
||||
let cancelConnect = (ownerUri: string): Thenable<boolean> => {
|
||||
return self._sharedServiceProxy.request(constants.cancelConnectRequest, [{
|
||||
ownerUri: ownerUri
|
||||
}]);
|
||||
};
|
||||
|
||||
let changeDatabase = (ownerUri: string, newDatabase: string): Thenable<boolean> => {
|
||||
return self._sharedServiceProxy.request(constants.changeDatabaseRequest, [{
|
||||
ownerUri: ownerUri,
|
||||
newDatabase: newDatabase
|
||||
}]);
|
||||
};
|
||||
|
||||
let listDatabases = (ownerUri: string): Thenable<azdata.ListDatabasesResult> => {
|
||||
return self._sharedServiceProxy.request(constants.listDatabasesRequest, [{
|
||||
ownerUri: ownerUri
|
||||
}]);
|
||||
};
|
||||
|
||||
let getConnectionString = (ownerUri: string, includePassword: boolean): Thenable<string> => {
|
||||
return self._sharedServiceProxy.request(constants.getConnectionStringRequest, [{
|
||||
ownerUri: ownerUri,
|
||||
includePassword: includePassword
|
||||
}]);
|
||||
};
|
||||
|
||||
let buildConnectionInfo = (connectionString: string): Thenable<azdata.ConnectionInfo> => {
|
||||
return self._sharedServiceProxy.request(constants.buildConnectionInfoRequest, [{
|
||||
connectionString: connectionString
|
||||
}]);
|
||||
};
|
||||
|
||||
let rebuildIntelliSenseCache = (ownerUri: string): Thenable<void> => {
|
||||
return self._sharedServiceProxy.request(constants.rebuildIntellisenseCacheRequest, [{
|
||||
ownerUri: ownerUri
|
||||
}]);
|
||||
};
|
||||
|
||||
let registerOnConnectionComplete = (handler: (connSummary: azdata.ConnectionInfoSummary) => any): void => {
|
||||
self._onConnectionCompleteHandler = handler;
|
||||
return;
|
||||
};
|
||||
|
||||
let registerOnIntelliSenseCacheComplete = (handler: (connectionUri: string) => any): void => {
|
||||
return;
|
||||
};
|
||||
|
||||
let registerOnConnectionChanged = (handler: (changedConnInfo: azdata.ChangedConnectionInfo) => any): void => {
|
||||
return;
|
||||
};
|
||||
|
||||
return azdata.dataprotocol.registerConnectionProvider({
|
||||
providerId: constants.LiveShareProviderId,
|
||||
connect,
|
||||
disconnect,
|
||||
cancelConnect,
|
||||
changeDatabase,
|
||||
listDatabases,
|
||||
getConnectionString,
|
||||
buildConnectionInfo,
|
||||
rebuildIntelliSenseCache,
|
||||
registerOnConnectionChanged,
|
||||
registerOnIntelliSenseCacheComplete,
|
||||
registerOnConnectionComplete
|
||||
});
|
||||
}
|
||||
}
|
||||
233
extensions/liveshare/src/providers/queryProvider.ts
Normal file
233
extensions/liveshare/src/providers/queryProvider.ts
Normal file
@@ -0,0 +1,233 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import * as constants from '../constants';
|
||||
import { SharedService, SharedServiceProxy } from '../liveshare';
|
||||
|
||||
export class QueryProvider {
|
||||
private _sharedService: SharedService;
|
||||
private _sharedServiceProxy: SharedServiceProxy;
|
||||
private _onQueryCompleteHandler: (result: azdata.QueryExecuteCompleteNotificationResult) => any;
|
||||
|
||||
public constructor(private _isHost: boolean) { }
|
||||
|
||||
public initialize(isHost: boolean, service: SharedService | SharedServiceProxy) {
|
||||
if (this._isHost) {
|
||||
this._sharedService = <SharedService>service;
|
||||
this.registerProviderListener();
|
||||
} else {
|
||||
this._sharedServiceProxy = <SharedServiceProxy>service;
|
||||
this.registerProvider();
|
||||
}
|
||||
}
|
||||
|
||||
public registerProviderListener() {
|
||||
this._sharedService.onRequest(constants.cancelQueryRequest, (args: any) => {
|
||||
return;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.runQueryRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.runQueryStatementRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.runQueryStringRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.runQueryAndReturnRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.parseSyntaxRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.getQueryRowsRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.disposeQueryRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.saveResultsRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
|
||||
this._sharedService.onRequest(constants.setQueryExecutionOptionsRequest, (args: any) => {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public registerProvider(): vscode.Disposable {
|
||||
const self = this;
|
||||
let runQuery = (ownerUri: string, querySelection: azdata.ISelectionData, executionPlanOptions?: azdata.ExecutionPlanOptions): Thenable<void> => {
|
||||
if (self._onQueryCompleteHandler) {
|
||||
self._onQueryCompleteHandler({
|
||||
ownerUri: ownerUri,
|
||||
batchSummaries: []
|
||||
});
|
||||
}
|
||||
|
||||
return self._sharedServiceProxy.request(constants.runQueryRequest, [{
|
||||
ownerUri: ownerUri,
|
||||
querySelection: querySelection,
|
||||
executionPlanOptions: executionPlanOptions
|
||||
}]);
|
||||
};
|
||||
|
||||
let cancelQuery = (ownerUri: string): Thenable<azdata.QueryCancelResult> => {
|
||||
return self._sharedServiceProxy.request(constants.cancelQueryRequest, [{
|
||||
ownerUri: ownerUri
|
||||
}]);
|
||||
};
|
||||
|
||||
let runQueryStatement = (ownerUri: string, line: number, column: number): Thenable<void> => {
|
||||
return self._sharedServiceProxy.request(constants.runQueryStatementRequest, [{
|
||||
ownerUri: ownerUri,
|
||||
line: line,
|
||||
column: column
|
||||
}]);
|
||||
};
|
||||
|
||||
let runQueryString = (ownerUri: string, query: string): Thenable<void> => {
|
||||
return self._sharedServiceProxy.request(constants.runQueryStringRequest, [{
|
||||
ownerUri: ownerUri,
|
||||
query: query
|
||||
}]);
|
||||
};
|
||||
|
||||
let runQueryAndReturn = (ownerUri: string, queryString: string): Thenable<azdata.SimpleExecuteResult> => {
|
||||
return self._sharedServiceProxy.request(constants.runQueryAndReturnRequest, [{
|
||||
ownerUri: ownerUri,
|
||||
query: queryString
|
||||
}]);
|
||||
};
|
||||
|
||||
let parseSyntax = (ownerUri: string, query: string): Thenable<azdata.SyntaxParseResult> => {
|
||||
return self._sharedServiceProxy.request(constants.parseSyntaxRequest, [{
|
||||
ownerUri: ownerUri,
|
||||
query: query
|
||||
}]);
|
||||
};
|
||||
|
||||
let getQueryRows = (rowData: azdata.QueryExecuteSubsetParams): Thenable<azdata.QueryExecuteSubsetResult> => {
|
||||
return self._sharedServiceProxy.request(constants.getQueryRowsRequest, [{
|
||||
rowData: rowData
|
||||
}]);
|
||||
};
|
||||
|
||||
let disposeQuery = (ownerUri: string): Thenable<void> => {
|
||||
return self._sharedServiceProxy.request(constants.disposeQueryRequest, [{
|
||||
ownerUri: ownerUri
|
||||
}]);
|
||||
};
|
||||
|
||||
let registerOnQueryComplete = (handler: (result: azdata.QueryExecuteCompleteNotificationResult) => any): void => {
|
||||
self._onQueryCompleteHandler = handler;
|
||||
};
|
||||
|
||||
let registerOnBatchStart = (handler: (batchInfo: azdata.QueryExecuteBatchNotificationParams) => any): void => {
|
||||
};
|
||||
|
||||
let registerOnBatchComplete = (handler: (batchInfo: azdata.QueryExecuteBatchNotificationParams) => any): void => {
|
||||
};
|
||||
|
||||
let registerOnResultSetAvailable = (handler: (resultSetInfo: azdata.QueryExecuteResultSetNotificationParams) => any): void => {
|
||||
};
|
||||
|
||||
let registerOnResultSetUpdated = (handler: (resultSetInfo: azdata.QueryExecuteResultSetNotificationParams) => any): void => {
|
||||
};
|
||||
|
||||
let registerOnMessage = (handler: (message: azdata.QueryExecuteMessageParams) => any): void => {
|
||||
};
|
||||
|
||||
let saveResults = (requestParams: azdata.SaveResultsRequestParams): Thenable<azdata.SaveResultRequestResult> => {
|
||||
return Promise.resolve(undefined);
|
||||
};
|
||||
|
||||
let setQueryExecutionOptions = (ownerUri: string, options: azdata.QueryExecutionOptions): Thenable<void> => {
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
// Edit Data Requests
|
||||
let commitEdit = (ownerUri: string): Thenable<void> => {
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
let createRow = (ownerUri: string): Thenable<azdata.EditCreateRowResult> => {
|
||||
return Promise.resolve(undefined);
|
||||
};
|
||||
|
||||
let deleteRow = (ownerUri: string, rowId: number): Thenable<void> => {
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
let disposeEdit = (ownerUri: string): Thenable<void> => {
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
let initializeEdit = (ownerUri: string, schemaName: string, objectName: string, objectType: string, LimitResults: number, queryString: string): Thenable<void> => {
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
let revertCell = (ownerUri: string, rowId: number, columnId: number): Thenable<azdata.EditRevertCellResult> => {
|
||||
return Promise.resolve(undefined);
|
||||
};
|
||||
|
||||
let revertRow = (ownerUri: string, rowId: number): Thenable<void> => {
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
let updateCell = (ownerUri: string, rowId: number, columnId: number, newValue: string): Thenable<azdata.EditUpdateCellResult> => {
|
||||
return Promise.resolve(undefined);
|
||||
};
|
||||
|
||||
let getEditRows = (rowData: azdata.EditSubsetParams): Thenable<azdata.EditSubsetResult> => {
|
||||
return Promise.resolve(undefined);
|
||||
};
|
||||
|
||||
// Edit Data Event Handlers
|
||||
let registerOnEditSessionReady = (handler: (ownerUri: string, success: boolean, message: string) => any): void => {
|
||||
};
|
||||
|
||||
return azdata.dataprotocol.registerQueryProvider({
|
||||
providerId: constants.LiveShareProviderId,
|
||||
cancelQuery,
|
||||
commitEdit,
|
||||
createRow,
|
||||
deleteRow,
|
||||
disposeEdit,
|
||||
disposeQuery,
|
||||
getEditRows,
|
||||
getQueryRows,
|
||||
setQueryExecutionOptions,
|
||||
initializeEdit,
|
||||
registerOnBatchComplete,
|
||||
registerOnBatchStart,
|
||||
registerOnEditSessionReady,
|
||||
registerOnMessage,
|
||||
registerOnQueryComplete,
|
||||
registerOnResultSetAvailable,
|
||||
registerOnResultSetUpdated,
|
||||
revertCell,
|
||||
revertRow,
|
||||
runQuery,
|
||||
runQueryAndReturn,
|
||||
parseSyntax,
|
||||
runQueryStatement,
|
||||
runQueryString,
|
||||
saveResults,
|
||||
updateCell
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
94
extensions/liveshare/src/providers/statusProvider.ts
Normal file
94
extensions/liveshare/src/providers/statusProvider.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import { LiveShare, SharedService, SharedServiceProxy } from '../liveshare';
|
||||
import { ConnectionProvider } from './connectionProvider';
|
||||
import { LiveShareProviderId } from '../constants';
|
||||
|
||||
export class LiveShareDocumentState {
|
||||
public isConnected: boolean;
|
||||
public serverName?: string;
|
||||
public databaseName?: string;
|
||||
}
|
||||
|
||||
export class StatusProvider {
|
||||
private _sharedService: SharedService;
|
||||
private _sharedServiceProxy: SharedServiceProxy;
|
||||
|
||||
public constructor(
|
||||
private _isHost: boolean,
|
||||
private _vslsApi: LiveShare,
|
||||
connectionProvider: ConnectionProvider,
|
||||
service: SharedService | SharedServiceProxy) {
|
||||
|
||||
if (this._isHost) {
|
||||
this._sharedService = <SharedService>service;
|
||||
this.registerStatusProvider();
|
||||
} else {
|
||||
this._sharedServiceProxy = <SharedServiceProxy>service;
|
||||
|
||||
connectionProvider.onConnect(async (args: any) => {
|
||||
if (args && args.ownerUri && args.profile) {
|
||||
let queryDocument = await azdata.queryeditor.getQueryDocument(args.ownerUri);
|
||||
if (queryDocument) {
|
||||
let connectionOptions: Map<string, any> = new Map<string, any>();
|
||||
connectionOptions['providerName'] = LiveShareProviderId;
|
||||
connectionOptions['serverName'] = args.profile.options['server'];
|
||||
connectionOptions['databaseName'] = args.profile.options['database'];
|
||||
connectionOptions['userName'] = 'liveshare';
|
||||
connectionOptions['password'] = 'liveshare';
|
||||
connectionOptions['authenticationType'] = 'liveshare';
|
||||
connectionOptions['savePassword'] = false;
|
||||
connectionOptions['saveProfile'] = false;
|
||||
let profile = azdata.connection.ConnectionProfile.createFrom(connectionOptions);
|
||||
queryDocument.connect(profile);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private registerStatusProvider(): void {
|
||||
let self = this;
|
||||
|
||||
// Retrieves the current document state associated with the URI parameter.
|
||||
// The URI will be in guest Live Share format and needs to be converted back
|
||||
// to the host file path format.
|
||||
this._sharedService.onRequest('getDocumentState', async (args: any[]) => {
|
||||
if (args && args.length > 0) {
|
||||
let ownerUri = vscode.Uri.parse(args[0].ownerUri);
|
||||
let localUri: vscode.Uri = self._vslsApi.convertSharedUriToLocal(ownerUri);
|
||||
let connection = await azdata.connection.getConnection(localUri.toString());
|
||||
|
||||
let serverName: string = 'liveshare';
|
||||
let databaseName: string = 'liveshare';
|
||||
if (connection) {
|
||||
serverName = connection.serverName;
|
||||
databaseName = connection.databaseName;
|
||||
}
|
||||
|
||||
let documentState: LiveShareDocumentState = {
|
||||
isConnected: true,
|
||||
serverName: serverName,
|
||||
databaseName: databaseName
|
||||
};
|
||||
return documentState;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
public getDocumentState(doc: vscode.TextDocument): Promise<LiveShareDocumentState> {
|
||||
if (!this._isHost) {
|
||||
return this._sharedServiceProxy.request('getDocumentState', [{
|
||||
ownerUri: doc.uri.toString()
|
||||
}]);
|
||||
} else {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
extensions/liveshare/src/typings/refs.d.ts
vendored
Normal file
8
extensions/liveshare/src/typings/refs.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path='../../../../src/sql/azdata.d.ts'/>
|
||||
/// <reference path='../../../../src/sql/azdata.proposed.d.ts'/>
|
||||
/// <reference path='../../../../src/vs/vscode.d.ts'/>
|
||||
12
extensions/liveshare/tsconfig.json
Normal file
12
extensions/liveshare/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "../shared.tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out",
|
||||
"strict": false,
|
||||
"noUnusedParameters": false,
|
||||
"noImplicitAny": false
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
1515
extensions/liveshare/yarn.lock
Normal file
1515
extensions/liveshare/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
22
product.json
22
product.json
@@ -59,6 +59,28 @@
|
||||
"msrvida.azdata-sanddance"
|
||||
]
|
||||
},
|
||||
"extensionAllowedProposedApi": [
|
||||
"ms-vscode.references-view",
|
||||
"ms-vsliveshare.vsliveshare",
|
||||
"ms-vsliveshare.cloudenv",
|
||||
"ms-vsliveshare.cloudenv-explorer",
|
||||
"GitHub.vscode-pull-request-github",
|
||||
"GitHub.vscode-pull-request-github-insiders",
|
||||
"Microsoft.vscode-nmake-tools",
|
||||
"ms-vscode-remote.remote-containers",
|
||||
"ms-vscode-remote.remote-containers-nightly",
|
||||
"ms-vscode-remote.remote-ssh",
|
||||
"ms-vscode-remote.remote-ssh-nightly",
|
||||
"ms-vscode-remote.remote-ssh-edit",
|
||||
"ms-vscode-remote.remote-ssh-edit-nightly",
|
||||
"ms-vscode-remote.remote-ssh-explorer",
|
||||
"ms-vscode-remote.remote-ssh-explorer-nightly",
|
||||
"ms-vscode-remote.remote-wsl",
|
||||
"ms-vscode-remote.remote-wsl-nightly",
|
||||
"ms-vscode-remote.vscode-remote-extensionpack",
|
||||
"ms-vscode-remote.vscode-remote-extensionpack-nightly",
|
||||
"ms-azuretools.vscode-docker"
|
||||
],
|
||||
"extensionsGallery": {
|
||||
"serviceUrl": "https://sqlopsextensions.blob.core.windows.net/marketplace/v1/extensionsGallery.json"
|
||||
}
|
||||
|
||||
7
src/sql/azdata.d.ts
vendored
7
src/sql/azdata.d.ts
vendored
@@ -33,7 +33,7 @@ declare module 'azdata' {
|
||||
|
||||
export function registerMetadataProvider(provider: MetadataProvider): vscode.Disposable;
|
||||
|
||||
export function registerQueryProvider(provider: QueryProvider): vscode.Disposable;
|
||||
export function registerQueryProvider(provider: QueryProvider, isLiveShare?: boolean): vscode.Disposable;
|
||||
|
||||
export function registerAdminServicesProvider(provider: AdminServicesProvider): vscode.Disposable;
|
||||
|
||||
@@ -93,7 +93,7 @@ declare module 'azdata' {
|
||||
azureTenantId?: string;
|
||||
options: { [name: string]: any };
|
||||
|
||||
static createFrom(options: any[]): ConnectionProfile;
|
||||
static createFrom(options: Map<string, any>): ConnectionProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3825,6 +3825,9 @@ declare module 'azdata' {
|
||||
// tab content is build using the modelview UI builder APIs
|
||||
// probably should rename DialogTab class since it is useful outside dialogs
|
||||
createQueryTab(tab: window.DialogTab): void;
|
||||
|
||||
// connect the query document using the given connection profile
|
||||
connect(connectionProfile: connection.ConnectionProfile): Thenable<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
2
src/sql/azdata.proposed.d.ts
vendored
2
src/sql/azdata.proposed.d.ts
vendored
@@ -25,6 +25,8 @@ declare module 'azdata' {
|
||||
* Register a connection event listener
|
||||
*/
|
||||
export function registerConnectionEventListener(listener: connection.ConnectionEventListener): void;
|
||||
|
||||
export function getConnection(uri: string): Thenable<ConnectionProfile>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -277,6 +277,8 @@ export interface IConnectionManagementService {
|
||||
* @returns array of connections
|
||||
*/
|
||||
getConnections(activeConnectionsOnly?: boolean): ConnectionProfile[];
|
||||
|
||||
getConnection(uri: string): ConnectionProfile;
|
||||
}
|
||||
|
||||
export enum RunQueryOnConnectionMode {
|
||||
|
||||
@@ -156,8 +156,6 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
return this._onLanguageFlavorChanged.event;
|
||||
}
|
||||
|
||||
private _providerCount: number = 0;
|
||||
|
||||
// Connection Provider Registration
|
||||
public registerProvider(providerId: string, provider: azdata.ConnectionProvider): void {
|
||||
if (!this._providers.has(providerId)) {
|
||||
@@ -1337,7 +1335,6 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
* @returns array of connections
|
||||
**/
|
||||
public getConnections(activeConnectionsOnly?: boolean): ConnectionProfile[] {
|
||||
|
||||
// 1. Active Connections
|
||||
const connections = this.getActiveConnections();
|
||||
|
||||
@@ -1368,6 +1365,20 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
return connections;
|
||||
}
|
||||
|
||||
public getConnection(uri: string): ConnectionProfile {
|
||||
const connections = this.getActiveConnections();
|
||||
if (connections) {
|
||||
for (let connection of connections) {
|
||||
let connectionUri = this.getConnectionUriFromId(connection.id);
|
||||
if (connectionUri === uri) {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private getConnectionsInGroup(group: ConnectionProfileGroup): ConnectionProfile[] {
|
||||
const connections = [];
|
||||
if (group) {
|
||||
|
||||
@@ -33,8 +33,7 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa
|
||||
|
||||
public constructor(
|
||||
capabilitiesService: ICapabilitiesService,
|
||||
model: string | azdata.IConnectionProfile
|
||||
) {
|
||||
model: string | azdata.IConnectionProfile) {
|
||||
super(capabilitiesService, model);
|
||||
if (model && !isString(model)) {
|
||||
this.groupId = model.groupId;
|
||||
|
||||
@@ -189,7 +189,14 @@ export class ConnectionStatusManager {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private isSharedSession(fileUri: string): boolean {
|
||||
return fileUri && fileUri.startsWith('vsls:');
|
||||
}
|
||||
|
||||
public isConnected(id: string): boolean {
|
||||
if (this.isSharedSession(id)) {
|
||||
return true;
|
||||
}
|
||||
return (id in this._connections && this._connections[id].connectionId && !!this._connections[id].connectionId);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ export class ProviderConnectionInfo extends Disposable implements azdata.Connect
|
||||
|
||||
public set providerName(name: string) {
|
||||
this._providerName = name;
|
||||
if (!this._serverCapabilities) {
|
||||
if (!this._serverCapabilities && this.capabilitiesService) {
|
||||
let capabilities = this.capabilitiesService.getCapabilities(this.providerName);
|
||||
if (capabilities) {
|
||||
this._serverCapabilities = capabilities.connection;
|
||||
@@ -192,6 +192,11 @@ export class ProviderConnectionInfo extends Disposable implements azdata.Connect
|
||||
}
|
||||
|
||||
public isPasswordRequired(): boolean {
|
||||
// if there is no provider capabilities metadata assume a password is not required
|
||||
if (!this._serverCapabilities) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let optionMetadata = this._serverCapabilities.connectionOptions.find(
|
||||
option => option.specialValueType === ConnectionOptionSpecialType.password);
|
||||
let isPasswordRequired: boolean = optionMetadata.isRequired;
|
||||
|
||||
@@ -294,4 +294,8 @@ export class TestConnectionManagementService implements IConnectionManagementSer
|
||||
getConnections(activeConnectionsOnly?: boolean): ConnectionProfile[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
getConnection(uri: string): ConnectionProfile {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,31 @@ export class MainThreadConnectionManagement extends Disposable implements MainTh
|
||||
return Promise.resolve(this._connectionManagementService.getConnections(activeConnectionsOnly).map(profile => this.convertToConnectionProfile(profile)));
|
||||
}
|
||||
|
||||
public $getConnection(uri: string): Thenable<azdata.connection.ConnectionProfile> {
|
||||
let profile = this._connectionManagementService.getConnection(uri);
|
||||
if (!profile) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
let connection: azdata.connection.ConnectionProfile = {
|
||||
providerId: profile.providerName,
|
||||
connectionId: profile.id,
|
||||
connectionName: profile.connectionName,
|
||||
serverName: profile.serverName,
|
||||
databaseName: profile.databaseName,
|
||||
userName: profile.userName,
|
||||
password: profile.password,
|
||||
authenticationType: profile.authenticationType,
|
||||
savePassword: profile.savePassword,
|
||||
groupFullName: profile.groupFullName,
|
||||
groupId: profile.groupId,
|
||||
saveProfile: profile.savePassword,
|
||||
azureTenantId: profile.azureTenantId,
|
||||
options: profile.options
|
||||
};
|
||||
return Promise.resolve(connection);
|
||||
}
|
||||
|
||||
public $getActiveConnections(): Thenable<azdata.connection.Connection[]> {
|
||||
return Promise.resolve(this._connectionManagementService.getActiveConnections().map(profile => this.convertConnection(profile)));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IQueryModelService } from 'sql/platform/query/common/queryModel';
|
||||
import * as azdata from 'azdata';
|
||||
import { IQueryManagementService } from 'sql/platform/query/common/queryManagement';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||
|
||||
@extHostNamedCustomer(SqlMainContext.MainThreadQueryEditor)
|
||||
export class MainThreadQueryEditor extends Disposable implements MainThreadQueryEditorShape {
|
||||
@@ -62,6 +64,36 @@ export class MainThreadQueryEditor extends Disposable implements MainThreadQuery
|
||||
});
|
||||
}
|
||||
|
||||
private static connectionProfileToIConnectionProfile(connection: azdata.connection.ConnectionProfile): IConnectionProfile {
|
||||
let profile: ConnectionProfile = new ConnectionProfile(undefined, undefined);
|
||||
profile.options = connection.options;
|
||||
profile.providerName = connection.options['providerName'];
|
||||
return profile.toIConnectionProfile();
|
||||
}
|
||||
|
||||
public $connectWithProfile(fileUri: string, connection: azdata.connection.ConnectionProfile): Thenable<void> {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
let editors = this._editorService.visibleControls.filter(resource => {
|
||||
return !!resource && resource.input.getResource().toString() === fileUri;
|
||||
});
|
||||
let editor = editors && editors.length > 0 ? editors[0] : undefined;
|
||||
|
||||
let options: IConnectionCompletionOptions = {
|
||||
params: { connectionType: ConnectionType.editor, runQueryOnCompletion: RunQueryOnConnectionMode.none, input: editor ? editor.input as any : undefined },
|
||||
saveTheConnection: false,
|
||||
showDashboard: false,
|
||||
showConnectionDialogOnError: false,
|
||||
showFirewallRuleOnError: false,
|
||||
};
|
||||
|
||||
let profile: IConnectionProfile = MainThreadQueryEditor.connectionProfileToIConnectionProfile(connection);
|
||||
let connectionResult = await this._connectionManagementService.connect(profile, fileUri, options);
|
||||
if (connectionResult && connectionResult.connected) {
|
||||
console.log(`editor ${fileUri} connected`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public $runQuery(fileUri: string, runCurrentQuery: boolean = true): void {
|
||||
let filteredEditors = this._editorService.visibleControls.filter(editor => editor.input.getResource().toString() === fileUri);
|
||||
if (filteredEditors && filteredEditors.length > 0) {
|
||||
|
||||
@@ -20,10 +20,6 @@ export class ExtHostConnectionManagement extends ExtHostConnectionManagementShap
|
||||
this._proxy = mainContext.getProxy(SqlMainContext.MainThreadConnectionManagement);
|
||||
}
|
||||
|
||||
public $getCurrentConnection(): Thenable<azdata.connection.ConnectionProfile> {
|
||||
return this._proxy.$getCurrentConnectionProfile();
|
||||
}
|
||||
|
||||
public $onConnectionEvent(handle: number, type: azdata.connection.ConnectionEventType, ownerUri: string, profile: azdata.IConnectionProfile): void {
|
||||
let listener = this._connectionListeners[handle];
|
||||
if (listener) {
|
||||
@@ -37,10 +33,18 @@ export class ExtHostConnectionManagement extends ExtHostConnectionManagementShap
|
||||
this._nextListenerHandle++;
|
||||
}
|
||||
|
||||
public $getCurrentConnection(): Thenable<azdata.connection.ConnectionProfile> {
|
||||
return this._proxy.$getCurrentConnectionProfile();
|
||||
}
|
||||
|
||||
public $getConnections(activeConnectionsOnly?: boolean): Thenable<azdata.connection.ConnectionProfile[]> {
|
||||
return this._proxy.$getConnections(activeConnectionsOnly);
|
||||
}
|
||||
|
||||
public $getConnection(uri: string): Thenable<azdata.connection.ConnectionProfile> {
|
||||
return this._proxy.$getConnection(uri);
|
||||
}
|
||||
|
||||
// "sqlops" back-compat connection APIs
|
||||
public $getActiveConnections(): Thenable<azdata.connection.Connection[]> {
|
||||
return this._proxy.$getActiveConnections();
|
||||
|
||||
@@ -251,6 +251,7 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
||||
if (this.uriTransformer) {
|
||||
ownerUri = URI.from(this.uriTransformer.transformIncoming(URI.parse(ownerUri))).toString(true);
|
||||
}
|
||||
|
||||
return this._resolveProvider<azdata.QueryProvider>(handle).runQuery(ownerUri, selection, runOptions);
|
||||
}
|
||||
|
||||
@@ -274,6 +275,10 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
||||
}
|
||||
}
|
||||
|
||||
$connectWithProfile(handle: number, ownerUri: string, profile: azdata.connection.ConnectionProfile): Thenable<void> {
|
||||
return new Promise((r) => r());
|
||||
}
|
||||
|
||||
$parseSyntax(handle: number, ownerUri: string, query: string): Thenable<azdata.SyntaxParseResult> {
|
||||
return this._resolveProvider<azdata.QueryProvider>(handle).parseSyntax(ownerUri, query);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,10 @@ class ExtHostQueryDocument implements azdata.queryeditor.QueryDocument {
|
||||
public createQueryTab(tab: azdata.window.DialogTab): void {
|
||||
this._proxy.$createQueryTab(this.uri, tab.title, tab.content);
|
||||
}
|
||||
|
||||
public connect(connectionProfile: azdata.connection.ConnectionProfile): Thenable<void> {
|
||||
return this._proxy.$connectWithProfile(this.uri, connectionProfile);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostQueryEditor implements ExtHostQueryEditorShape {
|
||||
|
||||
@@ -118,7 +118,9 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp
|
||||
registerConnectionEventListener(listener: azdata.connection.ConnectionEventListener): void {
|
||||
return extHostConnectionManagement.$registerConnectionEventListener(mssqlProviderName, listener);
|
||||
},
|
||||
|
||||
getConnection(uri: string): Thenable<azdata.connection.ConnectionProfile> {
|
||||
return extHostConnectionManagement.$getConnection(uri);
|
||||
},
|
||||
// "sqlops" back-compat APIs
|
||||
getActiveConnections(): Thenable<azdata.connection.Connection[]> {
|
||||
console.warn('the method azdata.connection.getActiveConnections has been deprecated, replace it with azdata.connection.getConnections');
|
||||
|
||||
@@ -180,6 +180,11 @@ export abstract class ExtHostDataProtocolShape {
|
||||
*/
|
||||
$setQueryExecutionOptions(handle: number, ownerUri: string, options: azdata.QueryExecutionOptions): Thenable<void> { throw ni(); }
|
||||
|
||||
/**
|
||||
* Connect the editor document to the given profile
|
||||
*/
|
||||
$connectWithProfile(handle: number, ownerUri: string, profile: azdata.connection.ConnectionProfile): Thenable<void> { throw ni(); }
|
||||
|
||||
/**
|
||||
* Disposes the cached information regarding a query
|
||||
*/
|
||||
@@ -578,6 +583,7 @@ export interface MainThreadDataProtocolShape extends IDisposable {
|
||||
export interface MainThreadConnectionManagementShape extends IDisposable {
|
||||
$registerConnectionEventListener(handle: number, providerId: string): void;
|
||||
$getConnections(activeConnectionsOnly?: boolean): Thenable<azdata.connection.ConnectionProfile[]>;
|
||||
$getConnection(uri: string): Thenable<azdata.connection.ConnectionProfile>;
|
||||
$getActiveConnections(): Thenable<azdata.connection.Connection[]>;
|
||||
$getCurrentConnection(): Thenable<azdata.connection.Connection>;
|
||||
$getCurrentConnectionProfile(): Thenable<azdata.connection.ConnectionProfile>;
|
||||
@@ -780,6 +786,7 @@ export interface ExtHostQueryEditorShape {
|
||||
|
||||
export interface MainThreadQueryEditorShape extends IDisposable {
|
||||
$connect(fileUri: string, connectionId: string): Thenable<void>;
|
||||
$connectWithProfile(fileUri: string, connectionProfile: azdata.connection.ConnectionProfile): Thenable<void>;
|
||||
$runQuery(fileUri: string, runCurrentQuery?: boolean): void;
|
||||
$createQueryTab(fileUri: string, title: string, content: string): void;
|
||||
$setQueryExecutionOptions(fileUri: string, options: azdata.QueryExecutionOptions): Thenable<void>;
|
||||
|
||||
@@ -564,25 +564,116 @@ export interface ISingleNotebookEditOperation {
|
||||
}
|
||||
|
||||
export class ConnectionProfile {
|
||||
get providerId(): string {
|
||||
return this.options['providerId'];
|
||||
}
|
||||
|
||||
providerId: string;
|
||||
connectionId: string;
|
||||
connectionName: string;
|
||||
serverName: string;
|
||||
databaseName: string;
|
||||
userName: string;
|
||||
password: string;
|
||||
authenticationType: string;
|
||||
savePassword: boolean;
|
||||
groupFullName: string;
|
||||
groupId: string;
|
||||
saveProfile: boolean;
|
||||
azureTenantId?: string;
|
||||
options: { [name: string]: any };
|
||||
set providerId(value: string) {
|
||||
this.options['providerId'] = value;
|
||||
}
|
||||
|
||||
static createFrom(options: any[]): ConnectionProfile {
|
||||
// create from options
|
||||
return undefined;
|
||||
get connectionId(): string {
|
||||
return this.options['connectionId'];
|
||||
}
|
||||
|
||||
set connectionId(value: string) {
|
||||
this.options['connectionId'] = value;
|
||||
}
|
||||
|
||||
get connectionName(): string {
|
||||
return this.options['connectionName'];
|
||||
}
|
||||
|
||||
set connectionName(value: string) {
|
||||
this.options['connectionName'] = value;
|
||||
}
|
||||
|
||||
get serverName(): string {
|
||||
return this.options['serverName'];
|
||||
}
|
||||
|
||||
set serverName(value: string) {
|
||||
this.options['serverName'] = value;
|
||||
}
|
||||
|
||||
get databaseName(): string {
|
||||
return this.options['databaseName'];
|
||||
}
|
||||
|
||||
set databaseName(value: string) {
|
||||
this.options['databaseName'] = value;
|
||||
}
|
||||
|
||||
get userName(): string {
|
||||
return this.options['userName'];
|
||||
}
|
||||
|
||||
set userName(value: string) {
|
||||
this.options['userName'] = value;
|
||||
}
|
||||
|
||||
get password(): string {
|
||||
return this.options['password'];
|
||||
}
|
||||
|
||||
set password(value: string) {
|
||||
this.options['password'] = value;
|
||||
}
|
||||
|
||||
get authenticationType(): string {
|
||||
return this.options['authenticationType'];
|
||||
}
|
||||
|
||||
set authenticationType(value: string) {
|
||||
this.options['authenticationType'] = value;
|
||||
}
|
||||
|
||||
get savePassword(): boolean {
|
||||
return this.options['savePassword'];
|
||||
}
|
||||
|
||||
set savePassword(value: boolean) {
|
||||
this.options['savePassword'] = value;
|
||||
}
|
||||
|
||||
get groupFullName(): string {
|
||||
return this.options['groupFullName'];
|
||||
}
|
||||
|
||||
set groupFullName(value: string) {
|
||||
this.options['groupFullName'] = value;
|
||||
}
|
||||
|
||||
get groupId(): string {
|
||||
return this.options['groupId'];
|
||||
}
|
||||
|
||||
set groupId(value: string) {
|
||||
this.options['groupId'] = value;
|
||||
}
|
||||
|
||||
get saveProfile(): boolean {
|
||||
return this.options['groupId'];
|
||||
}
|
||||
|
||||
set saveProfile(value: boolean) {
|
||||
this.options['groupId'] = value;
|
||||
}
|
||||
|
||||
get azureTenantId(): string {
|
||||
return this.options['azureTenantId'];
|
||||
}
|
||||
|
||||
set azureTenantId(value: string) {
|
||||
this.options['azureTenantId'] = value;
|
||||
}
|
||||
|
||||
options: Map<string, any> = new Map<string, any>();
|
||||
|
||||
static createFrom(options: Map<string, any>): ConnectionProfile {
|
||||
let profile = new ConnectionProfile();
|
||||
profile.options = options;
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -472,12 +472,14 @@ export class ToggleConnectDatabaseAction extends QueryTaskbarAction {
|
||||
}
|
||||
|
||||
public run(): Promise<void> {
|
||||
if (this.connected) {
|
||||
// Call disconnectEditor regardless of the connection state and let the ConnectionManagementService
|
||||
// determine if we need to disconnect, cancel an in-progress connection, or do nothing
|
||||
this.connectionManagementService.disconnectEditor(this.editor.input);
|
||||
} else {
|
||||
this.connectEditor(this.editor);
|
||||
if (!this.editor.input.isSharedSession) {
|
||||
if (this.connected) {
|
||||
// Call disconnectEditor regardless of the connection state and let the ConnectionManagementService
|
||||
// determine if we need to disconnect, cancel an in-progress connection, or do nothing
|
||||
this.connectionManagementService.disconnectEditor(this.editor.input);
|
||||
} else {
|
||||
this.connectEditor(this.editor);
|
||||
}
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
@@ -355,4 +355,8 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
|
||||
public get tabColor(): string {
|
||||
return this._connectionManagementService.getTabColorForUri(this.uri);
|
||||
}
|
||||
|
||||
public get isSharedSession(): boolean {
|
||||
return this.uri && this.uri.startsWith('vsls:');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user