Add the first version of whoisactive project (#943)

* add the first version of whoisactive

* address comments

* address comments

* fix the issues from the last commit

* clean up package.json
This commit is contained in:
Abbie Petchtes
2018-03-22 12:32:22 -07:00
committed by GitHub
parent 4cfd9bdbc0
commit 50c4fd79b7
35 changed files with 10130 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
'use strict';
// CONFIG VALUES ///////////////////////////////////////////////////////////
export const extensionConfigSectionName = 'extensionSamples';
export const configLogDebugInfo = 'logDebugInfo';

View File

@@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* 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 vscode from 'vscode';
export default abstract class ControllerBase implements vscode.Disposable {
protected _context: vscode.ExtensionContext;
public constructor(context: vscode.ExtensionContext) {
this._context = context;
}
abstract activate(): Promise<boolean>;
abstract deactivate(): void;
public dispose(): void {
this.deactivate();
}
}

View File

@@ -0,0 +1,63 @@
/*---------------------------------------------------------------------------------------------
* 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 sqlops from 'sqlops';
import * as Utils from '../utils';
import ControllerBase from './controllerBase';
import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import * as openurl from 'openurl';
/**
* The main controller class that initializes the extension
*/
export default class MainController extends ControllerBase {
public apiWrapper;
// PUBLIC METHODS //////////////////////////////////////////////////////
/**
* Deactivates the extension
*/
public deactivate(): void {
Utils.logDebug('Main controller deactivated');
}
public activate(): Promise<boolean> {
sqlops.dashboard.registerWebviewProvider('sp_whoisactive_documentation', webview => {
let templateValues = {url: 'http://whoisactive.com/docs/'};
Utils.renderTemplateHtml(path.join(__dirname, '..'), 'templateTab.html', templateValues)
.then(html => {
webview.html = html;
});
});
sqlops.tasks.registerTask('sp_whoisactive.install', e => this.onInstall(e));
sqlops.tasks.registerTask('sp_whoisactive.findBlockLeaders', e => this.onExecute(e, 'findBlockLeaders.sql'));
sqlops.tasks.registerTask('sp_whoisactive.getPlans', e => this.onExecute(e, 'getPlans.sql'));
return Promise.resolve(true);
}
private onInstall(connection: sqlops.IConnectionProfile): void {
openurl.open('http://whoisactive.com/downloads/');
}
private onExecute(connection: sqlops.IConnectionProfile, fileName: string): void {
let sqlFile = fs.readFileSync(path.join(__dirname, '..', 'sql', fileName)).toString();
this.openSQLFileWithContent(sqlFile);
}
private openSQLFileWithContent(content: string): void {
vscode.workspace.openTextDocument({language: 'sql', content: content}).then(doc => {
vscode.window.showTextDocument(doc, vscode.ViewColumn.Active, false);
});
}
}

View File

@@ -0,0 +1,39 @@
/*---------------------------------------------------------------------------------------------
* 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 vscode from 'vscode';
import ControllerBase from './controllers/controllerBase';
import MainController from './controllers/mainController';
let controllers: ControllerBase[] = [];
export function activate(context: vscode.ExtensionContext): Promise<boolean> {
let activations: Promise<boolean>[] = [];
// Start the main controller
let mainController = new MainController(context);
controllers.push(mainController);
context.subscriptions.push(mainController);
activations.push(mainController.activate());
return Promise.all(activations)
.then((results: boolean[]) => {
for (let result of results) {
if (!result) {
return false;
}
}
return true;
});
}
export function deactivate(): void {
for (let controller of controllers) {
controller.deactivate();
}
}

View File

@@ -0,0 +1,5 @@
'use strict';
// TODO: localize!
export const msgErrorLoadingTab = 'An error occurred while loading the tab.';

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>configure_dashboard</title><path d="M16,0V4H15V1.71L10.5,6.2l-3-3L0,10.71V9.29L7.5,1.8l3,3L14.29,1H12V0Zm-.12,10.93-1,.4a2.75,2.75,0,0,1,.06.33,3,3,0,0,1,0,.68,2.71,2.71,0,0,1-.06.33l1,.4L15.5,14l-1-.4a3,3,0,0,1-.95.95l.4,1-.92.38-.4-1-.33.06L12,15l-.34,0-.33-.06-.4,1L10,15.5l.4-1a2.93,2.93,0,0,1-.95-.95l-1,.4-.38-.92,1-.4a3.25,3.25,0,0,1,0-1.34l-1-.4L8.49,10l1,.4a2.83,2.83,0,0,1,.95-.95l-.4-1,.92-.38.4,1a3.25,3.25,0,0,1,1.34,0l.4-1,.92.38-.4,1a3,3,0,0,1,.53.42,3,3,0,0,1,.42.53l1-.4ZM12,14a1.94,1.94,0,0,0,.78-.16,2,2,0,0,0,1.07-1.07,2,2,0,0,0,0-1.55,2,2,0,0,0-1.07-1.07,2,2,0,0,0-1.55,0,2,2,0,0,0-1.07,1.07,2,2,0,0,0,0,1.55,2,2,0,0,0,1.07,1.07A1.94,1.94,0,0,0,12,14Z"/></svg>

After

Width:  |  Height:  |  Size: 781 B

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{font-size:12px;font-family:FullMDL2Assets, Full MDL2 Assets;}.cls-1,.cls-2{fill:#fff;}</style></defs><title>manage_inverse_16x16 </title><text class="cls-1" transform="translate(0.01 11.59)"> </text><path class="cls-2" d="M16,0V4H15V1.71L10.5,6.2l-3-3L0,10.71V9.29L7.5,1.8l3,3L14.29,1H12V0Zm-.12,10.93-1,.4a2.75,2.75,0,0,1,.06.33,3,3,0,0,1,0,.68,2.71,2.71,0,0,1-.06.33l1,.4L15.5,14l-1-.4a3,3,0,0,1-.95.95l.4,1-.92.38-.4-1-.33.06L12,15l-.34,0-.33-.06-.4,1L10,15.5l.4-1a2.93,2.93,0,0,1-.95-.95l-1,.4-.38-.92,1-.4a3.25,3.25,0,0,1,0-1.34l-1-.4L8.49,10l1,.4a2.83,2.83,0,0,1,.95-.95l-.4-1,.92-.38.4,1a3.25,3.25,0,0,1,1.34,0l.4-1,.92.38-.4,1a3,3,0,0,1,.53.42,3,3,0,0,1,.42.53l1-.4ZM12,14a1.94,1.94,0,0,0,.78-.16,2,2,0,0,0,1.07-1.07,2,2,0,0,0,0-1.55,2,2,0,0,0-1.07-1.07,2,2,0,0,0-1.55,0,2,2,0,0,0-1.07,1.07,2,2,0,0,0,0,1.55,2,2,0,0,0,1.07,1.07A1.94,1.94,0,0,0,12,14Z"/></svg>

After

Width:  |  Height:  |  Size: 980 B

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#231f20;}.cls-2{fill:#212121;}</style></defs><title>file_16x16</title><polygon class="cls-1" points="13.59 2.21 13.58 2.22 13.58 2.2 13.59 2.21"/><path class="cls-2" d="M8.71,0,14,5.29V16H2V0ZM3,15H13V6H8V1H3ZM9,1.71V5h3.29Z"/></svg>

After

Width:  |  Height:  |  Size: 351 B

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>file_inverse_16x16</title><polygon class="cls-1" points="13.59 2.21 13.58 2.22 13.58 2.2 13.59 2.21"/><path class="cls-1" d="M8.71,0,14,5.29V16H2V0ZM3,15H13V6H8V1H3ZM9,1.71V5h3.29Z"/></svg>

After

Width:  |  Height:  |  Size: 335 B

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>query_plan_16x16</title><path d="M13.16,10.59h1.9v5H10.32v-5h1.89v-2H3.68v2H5.58v5H.84v-5h1.9v-3H7.47v-2H5.58v-5h4.74v5H8.42v2h4.74Zm-8.53,4v-3H1.79v3Zm1.9-13v3H9.37v-3Zm7.58,13v-3H11.26v3Z"/></svg>

After

Width:  |  Height:  |  Size: 298 B

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>query_plan_inverse_16x16</title><path class="cls-1" d="M13.06,10.49H15v5H10.22v-5h1.89v-2H3.59v2H5.48v5H.75v-5h1.9v-3H7.38v-2H5.48v-5h4.74v5H8.33v2h4.74Zm-8.53,4v-3H1.69v3Zm1.9-13v3H9.27v-3Zm7.58,13v-3H11.17v3Z"/></svg>

After

Width:  |  Height:  |  Size: 365 B

View File

@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#3bb44a;}</style></defs><title>run</title><path class="cls-1" d="M3.24,0,14.61,8,3.24,16Zm2,12.07L11.13,8,5.24,3.88Z"/><path class="cls-1" d="M3.74,1l10,7-10,7Zm1,1.92V13.07L12,8Z"/></svg>

After

Width:  |  Height:  |  Size: 306 B

View File

@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script type="text/javascript">
window.onload = function() {
document.getElementById('frame').src = "{{{url}}}";
};
</script>
<style>
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
#frame {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
</style>
</head>
<body>
<iframe id="frame" width="100%" height="100%" frameborder="0"></iframe>
</body>
</html>

View File

@@ -0,0 +1,8 @@
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'sp_WhoIsActive')
EXEC sp_WhoIsActive
@delta_interval = 1,
@output_column_list = '[session_id][CPU_delta]',
@sort_order = '[CPU_delta] DESC'
ELSE
SELECT 0;
GO

View File

@@ -0,0 +1,7 @@
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'sp_WhoIsActive')
EXEC sp_WhoIsActive
@output_column_list = '[session_id][CPU]',
@sort_order = '[CPU] DESC'
ELSE
SELECT 0;
GO

View File

@@ -0,0 +1,6 @@
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'sp_WhoIsActive')
EXEC sp_WhoIsActive
@find_block_leaders = 1,
@get_plans = 1,
@sort_order = '[blocked_session_count] DESC'
GO

View File

@@ -0,0 +1,4 @@
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'sp_WhoIsActive')
EXEC sp_WhoIsActive
@get_plans = 1
GO

View File

@@ -0,0 +1,8 @@
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'sp_WhoIsActive')
EXEC sp_WhoIsActive
@delta_interval = 1,
@output_column_list = '[session_id][used_memory_delta]',
@sort_order = '[used_memory_delta] DESC'
ELSE
SELECT 0;
GO

View File

@@ -0,0 +1,7 @@
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'sp_WhoIsActive')
EXEC sp_WhoIsActive
@output_column_list = '[session_id][used_memory]',
@sort_order = '[used_memory] DESC'
ELSE
SELECT 0;
GO

View File

@@ -0,0 +1,45 @@
'use strict';
import * as fs from 'fs-extra';
import * as handlebars from 'handlebars';
import * as path from 'path';
import * as vscode from 'vscode';
import * as Constants from './constants';
import * as LocalizedConstants from './localizedConstants';
/**
* Helper to log messages to the developer console if enabled
* @param msg Message to log to the console
*/
export function logDebug(msg: any): void {
let config = vscode.workspace.getConfiguration(Constants.extensionConfigSectionName);
let logDebugInfo = config[Constants.configLogDebugInfo];
if (logDebugInfo === true) {
let currentTime = new Date().toLocaleTimeString();
let outputMsg = '[' + currentTime + ']: ' + msg ? msg.toString() : '';
console.log(outputMsg);
}
}
export function renderTemplateHtml(extensionPath: string, templateName: string, templateValues: object): Thenable<string> {
let templatePath = path.join(extensionPath, 'resources', templateName);
// 1) Read the template from the disk
// 2) Compile it as a handlebars template and render the HTML
// 3) On failure, return a simple string as an error
return fs.readFile(templatePath, 'utf-8')
.then(templateText => {
let template = handlebars.compile(templateText);
return template(templateValues);
})
.then(
undefined,
error => {
logDebug(error);
return LocalizedConstants.msgErrorLoadingTab;
}
);
}