Skip to content

Commit

Permalink
Add embedded Getting Started guide (#120)
Browse files Browse the repository at this point in the history
* Add prompt to view embedded release notes.

* Add Getting Started guide.

* Correct the display condition
  • Loading branch information
kburtram authored Sep 28, 2016
1 parent 7e72d7b commit 44e0879
Show file tree
Hide file tree
Showing 10 changed files with 248 additions and 22 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ out
node_modules
packages
.DS_Store
*.dat
*.db
*.exe
*.log
Expand Down
1 change: 1 addition & 0 deletions .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ tasks/**
packages/**
samples/**
*.exe
*.dat
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.0.5",
"displayname": "MSSQL support in VS Code",
"description": "Connect to SQL Server and Azure SQL databases, run T-SQL queries and see results in a grid.",
"publisher": "microsoft",
"publisher": "Microsoft",
"license": "SEE LICENSE IN LICENSE.txt",
"aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412",
"icon": "images/sqlserver.png",
Expand Down Expand Up @@ -139,6 +139,11 @@
"command": "extension.openConnectionSettingsFile",
"title": "Open Connection Profile Settings",
"category": "MSSQL"
},
{
"command": "extension.showReleaseNotes",
"title": "Getting Started Guide",
"category": "MSSQL"
}
],
"keybindings": [
Expand Down
141 changes: 125 additions & 16 deletions src/controllers/controller.ts → src/controllers/mainController.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

'use strict';
import * as events from 'events';
import vscode = require('vscode');

import Constants = require('../models/constants');
import Utils = require('../models/utils');
import { SqlOutputContentProvider } from '../models/sqlOutputContentProvider';
Expand All @@ -13,7 +17,11 @@ import CodeAdapter from '../prompts/adapter';
import Telemetry from '../models/telemetry';
import VscodeWrapper from './vscodeWrapper';
import { ISelectionData } from './../models/interfaces';
import fs = require('fs');

/**
* The main controller class that initializes the extension
*/
export default class MainController implements vscode.Disposable {
private _context: vscode.ExtensionContext;
private _event: events.EventEmitter = new events.EventEmitter();
Expand All @@ -24,6 +32,10 @@ export default class MainController implements vscode.Disposable {
private _vscodeWrapper: VscodeWrapper;
private _initialized: boolean = false;

/**
* The main controller constructor
* @constructor
*/
constructor(context: vscode.ExtensionContext,
connectionManager?: ConnectionManager,
vscodeWrapper?: VscodeWrapper) {
Expand All @@ -36,23 +48,35 @@ export default class MainController implements vscode.Disposable {
}
}

/**
* Helper method to setup command registrations
*/
private registerCommand(command: string): void {
const self = this;
this._context.subscriptions.push(vscode.commands.registerCommand(command, () => {
self._event.emit(command);
}));
}

/**
* Disposes the controller
*/
dispose(): void {
this.deactivate();
}

/**
* Deactivates the extension
*/
public deactivate(): void {
Utils.logDebug(Constants.extensionDeactivated);
this.onDisconnect();
this._statusview.dispose();
}

/**
* Initializes the extension
*/
public activate(): Promise<boolean> {
const self = this;

Expand All @@ -73,65 +97,85 @@ export default class MainController implements vscode.Disposable {
this._event.on(Constants.cmdChooseDatabase, () => { self.onChooseDatabase(); } );
this.registerCommand(Constants.cmdOpenConnectionSettings);
this._event.on(Constants.cmdOpenConnectionSettings, () => { self.onOpenConnectionSettings(); } );
this.registerCommand(Constants.cmdShowReleaseNotes);
this._event.on(Constants.cmdShowReleaseNotes, () => { self.launchReleaseNotesPage(); } );

this._vscodeWrapper = new VscodeWrapper();

return this.initialize(activationTimer);
}

/**
* Returns a flag indicating if the extension is initialized
*/
public isInitialized(): boolean {
return this._initialized;
}

/**
* Initializes the extension
*/
public initialize(activationTimer: Utils.Timer): Promise<boolean> {
const self = this;

// initialize language service client
return new Promise<boolean>( (resolve, reject) => {
SqlToolsServerClient.instance.initialize(this._context).then(() => {
const self = this;
SqlToolsServerClient.instance.initialize(self._context).then(() => {

// Init status bar
this._statusview = new StatusView();
self._statusview = new StatusView();

// Init CodeAdapter for use when user response to questions is needed
this._prompter = new CodeAdapter();
self._prompter = new CodeAdapter();

// Init content provider for results pane
this._outputContentProvider = new SqlOutputContentProvider(self._context, self._statusview);
self._outputContentProvider = new SqlOutputContentProvider(self._context, self._statusview);
let registration = vscode.workspace.registerTextDocumentContentProvider(SqlOutputContentProvider.providerName, self._outputContentProvider);
this._context.subscriptions.push(registration);
self._context.subscriptions.push(registration);

// Init connection manager and connection MRU
this._connectionMgr = new ConnectionManager(self._context, self._statusview, self._prompter);
self._connectionMgr = new ConnectionManager(self._context, self._statusview, self._prompter);

activationTimer.end();

// telemetry for activation
Telemetry.sendTelemetryEvent(this._context, 'ExtensionActivated', {},
Telemetry.sendTelemetryEvent(self._context, 'ExtensionActivated', {},
{ activationTime: activationTimer.getDuration() }
);

self.showReleaseNotesPrompt();

Utils.logDebug(Constants.extensionActivated);
this._initialized = true;
self._initialized = true;
resolve(true);
});
});
}

// Choose a new database from the current server
/**
* Choose a new database from the current server
*/
private onChooseDatabase(): Promise<boolean> {
return this._connectionMgr.onChooseDatabase();
}

// Close active connection, if any
/**
* Close active connection, if any
*/
private onDisconnect(): Promise<any> {
return this._connectionMgr.onDisconnect();
}

// Let users pick from a list of connections
/**
* Let users pick from a list of connections
*/
public onNewConnection(): Promise<boolean> {
return this._connectionMgr.onNewConnection();
}

// get the T-SQL query from the editor, run it and show output
/**
* get the T-SQL query from the editor, run it and show output
*/
public onRunQuery(): void {
const self = this;
if (!this._vscodeWrapper.isEditingSqlFile) {
Expand Down Expand Up @@ -171,12 +215,16 @@ export default class MainController implements vscode.Disposable {
}
}

// Prompts to create a new SQL connection profile
/**
* Prompts to create a new SQL connection profile
*/
public onCreateProfile(): Promise<boolean> {
return this._connectionMgr.onCreateProfile();
}

// Prompts to remove a registered SQL connection profile
/**
* Prompts to remove a registered SQL connection profile
*/
public onRemoveProfile(): Promise<boolean> {
return this._connectionMgr.onRemoveProfile();
}
Expand All @@ -188,6 +236,9 @@ export default class MainController implements vscode.Disposable {
this._connectionMgr.connectionUI.openConnectionProfileConfigFile();
}

/**
* Executes a callback and logs any errors raised
*/
private runAndLogErrors<T>(promise: Promise<T>): Promise<T> {
let self = this;
return promise.catch(err => {
Expand All @@ -201,4 +252,62 @@ export default class MainController implements vscode.Disposable {
public get connectionManager(): ConnectionManager {
return this._connectionMgr;
}

/**
* Prompt the user to view release notes if this is new extension install
*/
private showReleaseNotesPrompt(): void {
let self = this;
if (!this.doesExtensionLaunchedFileExist()) {
// ask the user to view a scenario document
let confirmText = 'View Now';
this._vscodeWrapper.showInformationMessage(
'View a walkthrough of common vscode-mssql scenarios?', confirmText)
.then((choice) => {
if (choice === confirmText) {
self.launchReleaseNotesPage();
}
});
}
}

/**
* Shows the release notes page in the preview browser
*/
private launchReleaseNotesPage(): void {
// get the URI for the release notes page
let docUri = vscode.Uri.file(
this._context.asAbsolutePath(
'out/src/views/htmlcontent/src/docs/index.html'));

// show the release notes page in the preview window
vscode.commands.executeCommand(
'vscode.previewHtml',
docUri,
vscode.ViewColumn.One,
'vscode-mssql Release Notes');
}

/**
* Check if the extension launched file exists.
* This is to detect when we are running in a clean install scenario.
*/
private doesExtensionLaunchedFileExist(): boolean {
// check if file already exists on disk
let filePath = this._context.asAbsolutePath('extensionlaunched.dat');
try {
// this will throw if the file does not exist
fs.statSync(filePath);
return true;
} catch (err) {
try {
// write out the "first launch" file if it doesn't exist
fs.writeFile(filePath, 'launched');
} catch (err) {
// ignore errors writing first launch file since there isn't really
// anything we can do to recover in this situation.
}
return false;
}
}
}
6 changes: 4 additions & 2 deletions src/controllers/vscodeWrapper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import vscode = require('vscode');


import * as Constants from './../models/constants';

export import TextEditor = vscode.TextEditor;
Expand Down Expand Up @@ -156,8 +158,8 @@ export default class VscodeWrapper {
/**
* Formats and shows a vscode information message
*/
public showInformationMessage(msg: string): Thenable<string> {
return vscode.window.showInformationMessage(Constants.extensionName + ': ' + msg );
public showInformationMessage(msg: string, ...items: string[]): Thenable<string> {
return vscode.window.showInformationMessage(Constants.extensionName + ': ' + msg, ...items);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';
import vscode = require('vscode');
import MainController from './controllers/controller';
import MainController from './controllers/mainController';

let controller: MainController = undefined;

Expand Down
1 change: 1 addition & 0 deletions src/models/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const cmdCreateProfile = 'extension.createprofile';
export const cmdRemoveProfile = 'extension.removeprofile';
export const cmdChooseDatabase = 'extension.chooseDatabase';
export const cmdOpenConnectionSettings = 'extension.openConnectionSettingsFile';
export const cmdShowReleaseNotes = 'extension.showReleaseNotes';

export const sqlDbPrefix = '.database.windows.net';
export const defaultConnectionTimeout = 15;
Expand Down
107 changes: 107 additions & 0 deletions src/views/htmlcontent/src/docs/index.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion test/initialization.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import vscode = require('vscode');

import * as Extension from '../src/extension';
import ConnectionManager from '../src/controllers/connectionManager';
import MainController from '../src/controllers/controller';
import MainController from '../src/controllers/mainController';
import Telemetry from '../src/models/telemetry';

function ensureExtensionIsActive(): Promise<any> {
Expand Down
2 changes: 1 addition & 1 deletion test/perFileConnection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { IPrompter } from '../src/prompts/question';
import ConnectionManager from '../src/controllers/connectionManager';
import { IConnectionCredentials, AuthenticationTypes } from '../src/models/interfaces';
import * as ConnectionContracts from '../src/models/contracts/connection';
import MainController from '../src/controllers/controller';
import MainController from '../src/controllers/mainController';
import * as Interfaces from '../src/models/interfaces';
import { ConnectionStore } from '../src/models/connectionStore';
import StatusView from '../src/views/statusView';
Expand Down

0 comments on commit 44e0879

Please sign in to comment.