Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cccb9327c7 | ||
|
|
a0db32a688 | ||
|
|
f0b6180e15 | ||
|
|
cd4660abaa | ||
|
|
8320686170 | ||
|
|
0a6779f96e | ||
|
|
3e17618056 | ||
|
|
7d27d2f4f4 | ||
|
|
30ae023d73 | ||
|
|
c36596d3b3 | ||
|
|
afbe004c4f | ||
|
|
539f2b2b2e | ||
|
|
43e360165f | ||
|
|
c2727264ad | ||
|
|
3c17ac1333 | ||
|
|
218dad1b17 | ||
|
|
2ff4b51fe6 | ||
|
|
423ad40210 | ||
|
|
788103b2d3 | ||
|
|
c4ce709dfb | ||
|
|
e875e4a271 | ||
|
|
ba99be6ec1 | ||
|
|
146aa48c51 | ||
|
|
60f82785c2 |
@@ -65,6 +65,7 @@ const indentationFilter = [
|
||||
|
||||
// except multiple specific files
|
||||
'!**/package.json',
|
||||
'!**/package-lock.json', // {{SQL CARBON EDIT}}
|
||||
'!**/yarn.lock',
|
||||
'!**/yarn-error.log',
|
||||
|
||||
@@ -158,6 +159,7 @@ const copyrightFilter = [
|
||||
'!extensions/notebook/src/prompts/**',
|
||||
'!extensions/mssql/src/prompts/**',
|
||||
'!extensions/notebook/resources/jupyter_config/**',
|
||||
'!extensions/query-history/images/**',
|
||||
'!**/*.gif',
|
||||
'!**/*.xlf',
|
||||
'!**/*.dacpac',
|
||||
|
||||
@@ -199,7 +199,8 @@ const sqlBuiltInExtensions = [
|
||||
'admin-pack',
|
||||
'dacpac',
|
||||
'schema-compare',
|
||||
'cms'
|
||||
'cms',
|
||||
'query-history'
|
||||
];
|
||||
// make resource deployment and BDC extension only available in insiders
|
||||
if (process.env['VSCODE_QUALITY'] === 'stable') {
|
||||
|
||||
@@ -235,7 +235,8 @@ const sqlBuiltInExtensions = [
|
||||
'admin-pack',
|
||||
'dacpac',
|
||||
'schema-compare',
|
||||
'cms'
|
||||
'cms',
|
||||
'query-history'
|
||||
];
|
||||
|
||||
// make resource deployment and BDC extension only available in insiders
|
||||
|
||||
@@ -1,93 +1,93 @@
|
||||
{
|
||||
"name": "agent",
|
||||
"displayName": "SQL Server Agent",
|
||||
"description": "Manage and troubleshoot SQL Server Agent jobs",
|
||||
"version": "0.42.0",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
|
||||
"icon": "images/sqlserver.png",
|
||||
"aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412",
|
||||
"engines": {
|
||||
"vscode": "^1.25.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"main": "./out/main",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/azuredatastudio.git"
|
||||
},
|
||||
"extensionDependencies": [
|
||||
"Microsoft.mssql"
|
||||
],
|
||||
"contributes": {
|
||||
"outputChannels": [
|
||||
"sqlagent"
|
||||
],
|
||||
"dashboard.tabs": [
|
||||
{
|
||||
"id": "data-management-agent",
|
||||
"description": "Manage and troubleshoot SQL Agent jobs",
|
||||
"provider": "MSSQL",
|
||||
"title": "SQL Agent",
|
||||
"when": "connectionProvider == 'MSSQL' && !mssql:iscloud",
|
||||
"container": {
|
||||
"controlhost-container": {
|
||||
"type": "agent"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command": "agent.openNotebookDialog",
|
||||
"title": "Schedule Notebook",
|
||||
"icon": {
|
||||
"dark": "resources/dark/open_notebook_inverse.svg",
|
||||
"light": "resources/light/open_notebook.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "agent.reuploadTemplate",
|
||||
"title": "Reupload Template",
|
||||
"icon": {
|
||||
"dark": "resources/dark/open_notebook_inverse.svg",
|
||||
"light": "resources/light/open_notebook.svg"
|
||||
}
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"notebook/toolbar": [
|
||||
{
|
||||
"command": "agent.openNotebookDialog",
|
||||
"when": "providerId == sql"
|
||||
},
|
||||
{
|
||||
"command": "agent.reuploadTemplate",
|
||||
"when": "agent:trackedTemplate"
|
||||
}
|
||||
],
|
||||
"explorer/context": [
|
||||
{
|
||||
"command": "agent.openNotebookDialog",
|
||||
"when": "resourceExtname == .ipynb"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-nls": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha-junit-reporter": "^1.17.0",
|
||||
"mocha-multi-reporters": "^1.1.7",
|
||||
"@types/mocha": "^5.2.5",
|
||||
"@types/node": "^8.10.25",
|
||||
"mocha": "^5.2.0",
|
||||
"should": "^13.2.1",
|
||||
"typemoq": "^2.1.0",
|
||||
"name": "agent",
|
||||
"displayName": "SQL Server Agent",
|
||||
"description": "Manage and troubleshoot SQL Server Agent jobs",
|
||||
"version": "0.43.0",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
|
||||
"icon": "images/sqlserver.png",
|
||||
"aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412",
|
||||
"engines": {
|
||||
"vscode": "^1.25.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"main": "./out/main",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/azuredatastudio.git"
|
||||
},
|
||||
"extensionDependencies": [
|
||||
"Microsoft.mssql"
|
||||
],
|
||||
"contributes": {
|
||||
"outputChannels": [
|
||||
"sqlagent"
|
||||
],
|
||||
"dashboard.tabs": [
|
||||
{
|
||||
"id": "data-management-agent",
|
||||
"description": "Manage and troubleshoot SQL Agent jobs",
|
||||
"provider": "MSSQL",
|
||||
"title": "SQL Agent",
|
||||
"when": "connectionProvider == 'MSSQL' && !mssql:iscloud",
|
||||
"container": {
|
||||
"controlhost-container": {
|
||||
"type": "agent"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command": "agent.openNotebookDialog",
|
||||
"title": "Schedule Notebook",
|
||||
"icon": {
|
||||
"dark": "resources/dark/open_notebook_inverse.svg",
|
||||
"light": "resources/light/open_notebook.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "agent.reuploadTemplate",
|
||||
"title": "Update Template",
|
||||
"icon": {
|
||||
"dark": "resources/dark/open_notebook_inverse.svg",
|
||||
"light": "resources/light/open_notebook.svg"
|
||||
}
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"notebook/toolbar": [
|
||||
{
|
||||
"command": "agent.openNotebookDialog",
|
||||
"when": "providerId == sql && !agent:trackedTemplate"
|
||||
},
|
||||
{
|
||||
"command": "agent.reuploadTemplate",
|
||||
"when": "agent:trackedTemplate"
|
||||
}
|
||||
],
|
||||
"explorer/context": [
|
||||
{
|
||||
"command": "agent.openNotebookDialog",
|
||||
"when": "resourceExtname == .ipynb"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-nls": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha-junit-reporter": "^1.17.0",
|
||||
"mocha-multi-reporters": "^1.1.7",
|
||||
"@types/mocha": "^5.2.5",
|
||||
"@types/node": "^8.10.25",
|
||||
"mocha": "^5.2.0",
|
||||
"should": "^13.2.1",
|
||||
"typemoq": "^2.1.0",
|
||||
"vscode": "1.1.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -723,4 +723,4 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
this.model.alerts = this.alerts;
|
||||
this.model.categoryId = +this.model.jobCategoryIdsMap.find(cat => cat.name === this.model.category).id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +66,6 @@ export class NotebookDialog extends AgentDialog<NotebookData> {
|
||||
private removeScheduleButton: azdata.ButtonComponent;
|
||||
private descriptionTextBox: azdata.InputBoxComponent;
|
||||
|
||||
|
||||
|
||||
private isEdit: boolean = false;
|
||||
|
||||
// Job objects
|
||||
|
||||
@@ -70,3 +70,8 @@ export class IconPathHelper {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export namespace cssStyles {
|
||||
export const hyperlink = { 'user-select': 'text', 'color': '#0078d4', 'text-decoration': 'underline', 'cursor': 'pointer' };
|
||||
export const text = { 'margin-block-start': '0px', 'margin-block-end': '0px' };
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as nls from 'vscode-nls';
|
||||
import { BdcDashboardModel } from './bdcDashboardModel';
|
||||
import { IconPathHelper } from '../constants';
|
||||
import { IconPathHelper, cssStyles } from '../constants';
|
||||
import { getStateDisplayText, getHealthStatusDisplayText, getEndpointDisplayText, getHealthStatusIcon, getServiceNameDisplayText, Endpoint } from '../utils';
|
||||
import { EndpointModel, ServiceStatusModel, BdcStatusModel } from '../controller/apiGenerated';
|
||||
import { BdcDashboard } from './bdcDashboard';
|
||||
@@ -250,13 +250,21 @@ function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container:
|
||||
endPointRow.addItem(nameCell, { CSSStyles: { 'width': serviceEndpointRowServiceNameCellWidth, 'min-width': serviceEndpointRowServiceNameCellWidth, 'user-select': 'text', 'text-align': 'center' } });
|
||||
if (isHyperlink) {
|
||||
const endpointCell = modelBuilder.hyperlink()
|
||||
.withProperties({ label: endpoint.endpoint, url: endpoint.endpoint, CSSStyles: { 'height': '15px' } })
|
||||
.withProperties<azdata.HyperlinkComponentProperties>({
|
||||
label: endpoint.endpoint,
|
||||
title: endpoint.endpoint,
|
||||
url: endpoint.endpoint, CSSStyles: { 'height': '15px' }
|
||||
})
|
||||
.component();
|
||||
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'color': '#0078d4', 'text-decoration': 'underline', 'overflow': 'hidden', 'padding-left': '10px' } });
|
||||
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'overflow': 'hidden', 'text-overflow': 'ellipsis', ...cssStyles.hyperlink } });
|
||||
}
|
||||
else if (endpoint.name === Endpoint.sqlServerMaster) {
|
||||
const endpointCell = modelBuilder.text()
|
||||
.withProperties({ value: endpoint.endpoint, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text', 'cursor': 'pointer', 'color': '#0078d4', 'text-decoration': 'underline' } })
|
||||
.withProperties<azdata.TextComponentProperties>({
|
||||
value: endpoint.endpoint,
|
||||
title: endpoint.endpoint,
|
||||
CSSStyles: { 'overflow': 'hidden', 'text-overflow': 'ellipsis', ...cssStyles.text, ...cssStyles.hyperlink }
|
||||
})
|
||||
.component();
|
||||
endpointCell.onDidClick(async () => {
|
||||
const connProfile = bdcModel.getSqlServerMasterConnectionProfile();
|
||||
@@ -271,13 +279,17 @@ function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container:
|
||||
azdata.connection.openConnectionDialog(undefined, connProfile);
|
||||
}
|
||||
});
|
||||
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'overflow': 'hidden', 'padding-left': '10px' } });
|
||||
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth } });
|
||||
}
|
||||
else {
|
||||
const endpointCell = modelBuilder.text()
|
||||
.withProperties({ value: endpoint.endpoint, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } })
|
||||
.withProperties<azdata.TextComponentProperties>({
|
||||
value: endpoint.endpoint,
|
||||
title: endpoint.endpoint,
|
||||
CSSStyles: { 'overflow': 'hidden', 'text-overflow': 'ellipsis', ...cssStyles.text }
|
||||
})
|
||||
.component();
|
||||
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'overflow': 'hidden', 'padding-left': '10px' } });
|
||||
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth } });
|
||||
}
|
||||
const copyValueCell = modelBuilder.button().component();
|
||||
copyValueCell.iconPath = IconPathHelper.copy;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "import",
|
||||
"displayName": "SQL Server Import",
|
||||
"description": "SQL Server Import for Azure Data Studio supports importing CSV or JSON files into SQL Server.",
|
||||
"version": "0.10.0",
|
||||
"version": "0.11.0",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"engines": {
|
||||
@@ -50,6 +50,17 @@
|
||||
"group": "import"
|
||||
}
|
||||
]
|
||||
},
|
||||
"configuration":{
|
||||
"type": "object",
|
||||
"title": "%flatfileimport.configuration.title%",
|
||||
"properties": {
|
||||
"flatFileImport.logDebugInfo": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%flatfileimport.logDebugInfo%"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
4
extensions/import/package.nls.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"flatfileimport.configuration.title": "Flat File Import configuration",
|
||||
"flatfileimport.logDebugInfo": "[Optional] Log debug output to the console (View -> Output) and then select appropriate output channel from the dropdown"
|
||||
}
|
||||
@@ -44,7 +44,7 @@ export class ServiceClient {
|
||||
return new Promise((resolve, reject) => {
|
||||
serverdownloader.getOrDownloadServer().then(e => {
|
||||
const installationComplete = Date.now();
|
||||
let serverOptions = this.generateServerOptions(e);
|
||||
let serverOptions = this.generateServerOptions(e, context);
|
||||
client = new SqlOpsDataClient(Constants.serviceName, serverOptions, clientOptions);
|
||||
const processStart = Date.now();
|
||||
client.onReady().then(() => {
|
||||
@@ -90,10 +90,10 @@ export class ServiceClient {
|
||||
};
|
||||
}
|
||||
|
||||
private generateServerOptions(executablePath: string): ServerOptions {
|
||||
private generateServerOptions(executablePath: string, context: vscode.ExtensionContext): ServerOptions {
|
||||
let launchArgs = [];
|
||||
launchArgs.push('--log-dir');
|
||||
let logFileLocation = path.join(serviceUtils.getDefaultLogLocation(), 'flatfileimport');
|
||||
let logFileLocation = context.logPath;
|
||||
launchArgs.push(logFileLocation);
|
||||
let config = vscode.workspace.getConfiguration(Constants.extensionConfigSectionName);
|
||||
if (config) {
|
||||
|
||||
@@ -20,10 +20,6 @@ export function getAppDataPath(): string {
|
||||
}
|
||||
}
|
||||
|
||||
export function getDefaultLogLocation(): string {
|
||||
return path.join(getAppDataPath(), 'azuredatastudio');
|
||||
}
|
||||
|
||||
export function ensure(target: object, key: string): any {
|
||||
if (target[key] === void 0) {
|
||||
target[key] = {} as any;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
||||
"version": "2.0.0-release.10",
|
||||
"version": "2.0.0-release.17",
|
||||
"downloadFileNames": {
|
||||
"Windows_86": "win-x86-netcoreapp2.2.zip",
|
||||
"Windows_64": "win-x64-netcoreapp2.2.zip",
|
||||
|
||||
@@ -298,7 +298,7 @@ export namespace UpdateAgentNotebookRunNameRequest {
|
||||
}
|
||||
|
||||
export namespace DeleteMaterializedNotebookRequest {
|
||||
export const type = new RequestType<DeleteAgentMaterializedNotebookParams, azdata.ResultStatus, void, void>('agent/deletenotebookmaterialized');
|
||||
export const type = new RequestType<DeleteAgentMaterializedNotebookParams, azdata.ResultStatus, void, void>('agent/deletematerializednotebook');
|
||||
}
|
||||
|
||||
export namespace UpdateAgentNotebookRunPinRequest {
|
||||
|
||||
@@ -60,16 +60,28 @@ export function registerServiceEndpoints(context: vscode.ExtensionContext): void
|
||||
|
||||
const container = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '100%', height: '100%', alignItems: 'left' }).component();
|
||||
endpointsArray.forEach(endpointInfo => {
|
||||
|
||||
const endPointRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row' }).component();
|
||||
const nameCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: endpointInfo.description }).component();
|
||||
endPointRow.addItem(nameCell, { CSSStyles: { 'width': '35%', 'font-weight': '600', 'user-select': 'text' } });
|
||||
if (hyperlinkedEndpoints.findIndex(e => e === endpointInfo.serviceName) >= 0) {
|
||||
const linkCell = view.modelBuilder.hyperlink().withProperties<azdata.HyperlinkComponentProperties>({ label: endpointInfo.endpoint, url: endpointInfo.endpoint }).component();
|
||||
endPointRow.addItem(linkCell, { CSSStyles: { 'width': '62%', 'color': '#0078d4', 'text-decoration': 'underline', 'padding-top': '10px' } });
|
||||
const linkCell = view.modelBuilder.hyperlink()
|
||||
.withProperties<azdata.HyperlinkComponentProperties>({
|
||||
label: endpointInfo.endpoint,
|
||||
title: endpointInfo.endpoint,
|
||||
url: endpointInfo.endpoint
|
||||
}).component();
|
||||
endPointRow.addItem(linkCell, { CSSStyles: { 'width': '62%', 'color': '#0078d4', 'text-decoration': 'underline', 'padding-top': '10px', 'overflow': 'hidden', 'text-overflow': 'ellipsis' } });
|
||||
}
|
||||
else {
|
||||
const endpointCell = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: endpointInfo.endpoint }).component();
|
||||
const endpointCell =
|
||||
view.modelBuilder.text()
|
||||
.withProperties<azdata.TextComponentProperties>(
|
||||
{
|
||||
value: endpointInfo.endpoint,
|
||||
title: endpointInfo.endpoint,
|
||||
CSSStyles: { 'overflow': 'hidden', 'text-overflow': 'ellipsis' }
|
||||
})
|
||||
.component();
|
||||
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': '62%', 'user-select': 'text' } });
|
||||
}
|
||||
const copyValueCell = view.modelBuilder.button().component();
|
||||
|
||||
@@ -153,6 +153,13 @@
|
||||
"configuration": "./language-configuration.json"
|
||||
}
|
||||
],
|
||||
"grammars": [
|
||||
{
|
||||
"language": "notebook",
|
||||
"scopeName": "source.notebook",
|
||||
"path": "./syntaxes/notebook.tmLanguage.json"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"commandPalette": [
|
||||
{
|
||||
|
||||
213
extensions/notebook/syntaxes/notebook.tmLanguage.json
Normal file
@@ -0,0 +1,213 @@
|
||||
{
|
||||
"information_for_contributors": [
|
||||
"This file has been converted from https://github.com/Microsoft/vscode-JSON.tmLanguage/blob/master/JSON.tmLanguage",
|
||||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/Microsoft/vscode-JSON.tmLanguage/commit/9bd83f1c252b375e957203f21793316203f61f70",
|
||||
"name": "notebook",
|
||||
"scopeName": "source.notebook",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#value"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"array": {
|
||||
"begin": "\\[",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.array.begin.notebook"
|
||||
}
|
||||
},
|
||||
"end": "\\]",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.array.end.notebook"
|
||||
}
|
||||
},
|
||||
"name": "meta.structure.array.notebook",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#value"
|
||||
},
|
||||
{
|
||||
"match": ",",
|
||||
"name": "punctuation.separator.array.notebook"
|
||||
},
|
||||
{
|
||||
"match": "[^\\s\\]]",
|
||||
"name": "invalid.illegal.expected-array-separator.notebook"
|
||||
}
|
||||
]
|
||||
},
|
||||
"comments": {
|
||||
"patterns": [
|
||||
{
|
||||
"begin": "/\\*\\*(?!/)",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.comment.notebook"
|
||||
}
|
||||
},
|
||||
"end": "\\*/",
|
||||
"name": "comment.block.documentation.notebook"
|
||||
},
|
||||
{
|
||||
"begin": "/\\*",
|
||||
"captures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.comment.notebook"
|
||||
}
|
||||
},
|
||||
"end": "\\*/",
|
||||
"name": "comment.block.notebook"
|
||||
},
|
||||
{
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "punctuation.definition.comment.notebook"
|
||||
}
|
||||
},
|
||||
"match": "(//).*$\\n?",
|
||||
"name": "comment.line.double-slash.js"
|
||||
}
|
||||
]
|
||||
},
|
||||
"constant": {
|
||||
"match": "\\b(?:true|false|null)\\b",
|
||||
"name": "constant.language.notebook"
|
||||
},
|
||||
"number": {
|
||||
"match": "(?x) # turn on extended mode\n -? # an optional minus\n (?:\n 0 # a zero\n | # ...or...\n [1-9] # a 1-9 character\n \\d* # followed by zero or more digits\n )\n (?:\n (?:\n \\. # a period\n \\d+ # followed by one or more digits\n )?\n (?:\n [eE] # an e character\n [+-]? # followed by an option +/-\n \\d+ # followed by one or more digits\n )? # make exponent optional\n )? # make decimal portion optional",
|
||||
"name": "constant.numeric.notebook"
|
||||
},
|
||||
"object": {
|
||||
"begin": "\\{",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.dictionary.begin.notebook"
|
||||
}
|
||||
},
|
||||
"end": "\\}",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.dictionary.end.notebook"
|
||||
}
|
||||
},
|
||||
"name": "meta.structure.dictionary.notebook",
|
||||
"patterns": [
|
||||
{
|
||||
"comment": "the notebook object key",
|
||||
"include": "#objectkey"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
},
|
||||
{
|
||||
"begin": ":",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.separator.dictionary.key-value.notebook"
|
||||
}
|
||||
},
|
||||
"end": "(,)|(?=\\})",
|
||||
"endCaptures": {
|
||||
"1": {
|
||||
"name": "punctuation.separator.dictionary.pair.notebook"
|
||||
}
|
||||
},
|
||||
"name": "meta.structure.dictionary.value.notebook",
|
||||
"patterns": [
|
||||
{
|
||||
"comment": "the notebook object value",
|
||||
"include": "#value"
|
||||
},
|
||||
{
|
||||
"match": "[^\\s,]",
|
||||
"name": "invalid.illegal.expected-dictionary-separator.notebook"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"match": "[^\\s\\}]",
|
||||
"name": "invalid.illegal.expected-dictionary-separator.notebook"
|
||||
}
|
||||
]
|
||||
},
|
||||
"string": {
|
||||
"begin": "\"",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.begin.notebook"
|
||||
}
|
||||
},
|
||||
"end": "\"",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.definition.string.end.notebook"
|
||||
}
|
||||
},
|
||||
"name": "string.quoted.double.notebook",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#stringcontent"
|
||||
}
|
||||
]
|
||||
},
|
||||
"objectkey": {
|
||||
"begin": "\"",
|
||||
"beginCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.support.type.property-name.begin.notebook"
|
||||
}
|
||||
},
|
||||
"end": "\"",
|
||||
"endCaptures": {
|
||||
"0": {
|
||||
"name": "punctuation.support.type.property-name.end.notebook"
|
||||
}
|
||||
},
|
||||
"name": "string.notebook support.type.property-name.notebook",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#stringcontent"
|
||||
}
|
||||
]
|
||||
},
|
||||
"stringcontent": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "(?x) # turn on extended mode\n \\\\ # a literal backslash\n (?: # ...followed by...\n [\"\\\\/bfnrt] # one of these characters\n | # ...or...\n u # a u\n [0-9a-fA-F]{4}) # and four hex digits",
|
||||
"name": "constant.character.escape.notebook"
|
||||
},
|
||||
{
|
||||
"match": "\\\\.",
|
||||
"name": "invalid.illegal.unrecognized-string-escape.notebook"
|
||||
}
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#constant"
|
||||
},
|
||||
{
|
||||
"include": "#number"
|
||||
},
|
||||
{
|
||||
"include": "#string"
|
||||
},
|
||||
{
|
||||
"include": "#array"
|
||||
},
|
||||
{
|
||||
"include": "#object"
|
||||
},
|
||||
{
|
||||
"include": "#comments"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
1
extensions/query-history/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.vsix
|
||||
5
extensions/query-history/.vscodeignore
Normal file
@@ -0,0 +1,5 @@
|
||||
src/**
|
||||
.gitignore
|
||||
tsconfig.json
|
||||
cgmanifest.json
|
||||
.vscode
|
||||
50
extensions/query-history/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Query History *(preview)*
|
||||
|
||||
Adds a Query History panel for viewing and running past executed queries.
|
||||
|
||||
### How do I view the history?
|
||||
|
||||
Query History is displayed as a tab in the tab panel, which is toggled by the *View: Toggle Panel* command.
|
||||
|
||||

|
||||
|
||||
Initially this view will be empty but once you execute a query editor that will be captured in the window - with a separate row displayed for every query executed.
|
||||
|
||||

|
||||
|
||||
Each row consists of 3 parts :
|
||||
1. Status icon : This will be a ✔️ if the query executed successfully. If any errors occurred a ❌is shown.
|
||||
2. Query Text : This is the text of the query that was executed
|
||||
3. Connection Info : The Server and Database the query was executed against
|
||||
4. Timestamp : The date and time the query was executed
|
||||
|
||||
### Query History row actions
|
||||
|
||||
Right clicking on a history row will bring up a menu with a number of actions available.
|
||||
|
||||

|
||||
|
||||
#### Open Query
|
||||
|
||||
This will open a new query editor window populated with the query text from the query executed and using the connection of that query.
|
||||
|
||||
#### Run Query
|
||||
|
||||
This will do the same thing as Open Query but will additionally run the statement immediately.
|
||||
|
||||
#### Delete
|
||||
|
||||
This will permanently delete the row from the view.
|
||||
|
||||
## Code of Conduct
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Privacy Statement
|
||||
|
||||
The [Microsoft Enterprise and Developer Privacy Statement](https://privacy.microsoft.com/en-us/privacystatement) describes the privacy statement of this software.
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Licensed under the [Source EULA](https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt).
|
||||
BIN
extensions/query-history/images/QueryHistoryActionMenu.PNG
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
extensions/query-history/images/QueryHistoryTab.PNG
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
extensions/query-history/images/QueryHistoryTabWithQueries.PNG
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
extensions/query-history/images/sqlserver.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
54
extensions/query-history/package.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"name": "query-history",
|
||||
"displayName": "%queryHistory.displayName%",
|
||||
"description": "%queryHistory.description%",
|
||||
"version": "0.1.0",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt",
|
||||
"icon": "images/sqlserver.png",
|
||||
"aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412",
|
||||
"engines": {
|
||||
"vscode": "^1.30.1",
|
||||
"azdata": ">=1.12.0"
|
||||
},
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"main": "./out/main",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/azuredatastudio.git"
|
||||
},
|
||||
"extensionDependencies": [
|
||||
],
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "queryHistory.clear",
|
||||
"title": "%queryHistory.clear%",
|
||||
"category": "%queryHistory.displayName%"
|
||||
},
|
||||
{
|
||||
"command": "queryHistory.toggleCapture",
|
||||
"title": "%queryHistory.toggleCapture%",
|
||||
"category": "%queryHistory.displayName%"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "queryHistory.clear"
|
||||
},
|
||||
{
|
||||
"command": "queryHistory.toggleCapture"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
"vscode": "1.0.1"
|
||||
}
|
||||
}
|
||||
6
extensions/query-history/package.nls.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"queryHistory.displayName": "Query History",
|
||||
"queryHistory.description": "View and run previously executed queries",
|
||||
"queryHistory.clear": "Clear All History",
|
||||
"queryHistory.toggleCapture": "Toggle Query History Capture"
|
||||
}
|
||||
17
extensions/query-history/src/main.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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';
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<void> {
|
||||
// Currently all the functionality for this is contained within the core ADS
|
||||
// code as the extensibility API doesn't currently support all the required
|
||||
// functionality (such as contributing tab panels)
|
||||
vscode.commands.executeCommand('queryHistory.enableQueryHistory');
|
||||
}
|
||||
|
||||
export async function deactivate(): Promise<void> {
|
||||
|
||||
}
|
||||
6
extensions/query-history/src/typings/ref.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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/vs/vscode.d.ts'/>
|
||||
21
extensions/query-history/tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"outDir": "./out",
|
||||
"lib": [
|
||||
"es6", "es2015.promise"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node"
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
2307
extensions/query-history/yarn.lock
Normal file
@@ -23,7 +23,13 @@
|
||||
["\"", "\""],
|
||||
["'", "'"],
|
||||
["`", "`"]
|
||||
]
|
||||
],
|
||||
"folding": {
|
||||
"markers": {
|
||||
"start": "^\\s*--\\s*#region\\s*.*$",
|
||||
"end": "^\\s*--\\s*#endregion\\s*.*$"
|
||||
}
|
||||
}
|
||||
|
||||
// enhancedBrackets:[
|
||||
// { openTrigger: 'n', open: /begin$/i, closeComplete: 'end', matchCase: true },
|
||||
@@ -31,4 +37,4 @@
|
||||
// { openTrigger: 'n', open: /when$/i, closeComplete: 'then', matchCase: true }
|
||||
// ],
|
||||
// noindentBrackets: '()',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"Programming Languages"
|
||||
],
|
||||
"activationEvents": [
|
||||
"onLanguage:sql",
|
||||
"onLanguage:xml"
|
||||
],
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "azuredatastudio",
|
||||
"version": "1.11.0",
|
||||
"version": "1.12.1",
|
||||
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
|
||||
14301
samples/serverReports/package-lock.json
generated
@@ -1,236 +1,404 @@
|
||||
{
|
||||
"name": "server-report",
|
||||
"displayName": "Server Reports",
|
||||
"description": "Server Reports",
|
||||
"version": "0.1.5",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"engines": {
|
||||
"vscode": "^1.26.0",
|
||||
"azdata": "*"
|
||||
},
|
||||
"icon": "images/sqlserver.png",
|
||||
"license": "SEE LICENSE IN LICENSE.txt",
|
||||
"repository": "https://github.com/Microsoft/azuredatastudio",
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"main": "./out/src/extension",
|
||||
"contributes": {
|
||||
"configuration": [],
|
||||
"commands": [],
|
||||
"views": {},
|
||||
"menus": {},
|
||||
"dashboard.tabs": [
|
||||
{
|
||||
"id": "Server-Reports",
|
||||
"title": "Server Reports",
|
||||
"description": "This extension shows useful reports for a server.",
|
||||
"container": {
|
||||
"nav-section": [
|
||||
{
|
||||
"id": "server-reports-monitoring",
|
||||
"title": "Monitor",
|
||||
"icon": {
|
||||
"light": "./out/src/media/monitor.svg",
|
||||
"dark": "./out/src/media/monitor_inverse.svg"
|
||||
},
|
||||
"container": {
|
||||
"server-reports-monitoring-container": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "server-reports-performance",
|
||||
"title": "Performance",
|
||||
"icon": {
|
||||
"light": "./out/src/media/performance.svg",
|
||||
"dark": "./out/src/media/performance_inverse.svg"
|
||||
},
|
||||
"container": {
|
||||
"server-reports-performance-container": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"dashboard.insights": [
|
||||
{
|
||||
"id": "extension-dbspace-usage",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"horizontalBar": {
|
||||
"dataDirection": "vertical",
|
||||
"dataType": "number",
|
||||
"legendPosition": "top",
|
||||
"labelFirstColumn": false,
|
||||
"columnsAsLabels": true
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/all_db_space_used.sql"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "extension-cpu-utilization",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"timeSeries": {
|
||||
"dataDirection": "horizontal",
|
||||
"dataType": "point",
|
||||
"legendPosition": "top",
|
||||
"labelFirstColumn": false,
|
||||
"columnsAsLabels": false
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/cpumetric.sql"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "extension-backup-growth-trend",
|
||||
"details": "Abbie wants it",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"timeSeries": {
|
||||
"dataDirection": "horizontal",
|
||||
"dataType": "point",
|
||||
"legendPosition": "none",
|
||||
"labelFirstColumn": false,
|
||||
"columnsAsLabels": false
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/backup_size_trend.sql"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "extension-wait-counts-by-Paul-Randal",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"horizontalBar": {
|
||||
"dataDirection": "vertical",
|
||||
"dataType": "number",
|
||||
"legendPosition": "none",
|
||||
"labelFirstColumn": false,
|
||||
"columnsAsLabels": true
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/waits_paul_randal.sql",
|
||||
"details": {
|
||||
"queryFile": "./out/src/sql/waits_detail_paul_randal.sql",
|
||||
"label": {
|
||||
"column": "WaitType",
|
||||
"state": []
|
||||
},
|
||||
"value": "Percentage"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "extension-dbbuffer-usage",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"horizontalBar": {
|
||||
"dataDirection": "vertical",
|
||||
"dataType": "number",
|
||||
"legendPosition": "top",
|
||||
"labelFirstColumn": false,
|
||||
"columnsAsLabels": true
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/memorybydb.sql"
|
||||
}
|
||||
}
|
||||
],
|
||||
"dashboard.containers": [
|
||||
{
|
||||
"id": "server-reports-monitoring-container",
|
||||
"container": {
|
||||
"widgets-container": [
|
||||
{
|
||||
"name": "Top 10 DB Space Usage",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 2
|
||||
},
|
||||
"widget": {
|
||||
"extension-dbspace-usage": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top 10 DB Buffer Usage",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 2
|
||||
},
|
||||
"widget": {
|
||||
"extension-dbbuffer-usage": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CPU Utilization",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 1
|
||||
},
|
||||
"widget": {
|
||||
"extension-cpu-utilization": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Backup Growth Trend",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 1
|
||||
},
|
||||
"widget": {
|
||||
"extension-backup-growth-trend": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "server-reports-performance-container",
|
||||
"container": {
|
||||
"widgets-container": [
|
||||
{
|
||||
"name": "Wait Counts by Paul Randal",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 2
|
||||
},
|
||||
"widget": {
|
||||
"extension-wait-counts-by-Paul-Randal": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"snippets": []
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp build",
|
||||
"compile": "gulp compile",
|
||||
"watch": "gulp watch",
|
||||
"postinstall": "node ./node_modules/vscode/bin/install"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"child-process-promise": "^2.2.1",
|
||||
"del": "^3.0.0",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-color": "0.0.1",
|
||||
"gulp-sourcemaps": "^2.6.4",
|
||||
"gulp-tslint": "^6.0.2",
|
||||
"gulp-typescript": "^3.2.4",
|
||||
"should": "^13.2.1",
|
||||
"tslint": "^3.14.0",
|
||||
"typemoq": "^2.1.0",
|
||||
"typescript": "^2.6.1",
|
||||
"vsce": "1.36.2",
|
||||
"vscode": "^1.1.6"
|
||||
}
|
||||
}
|
||||
"name": "server-report",
|
||||
"displayName": "Server Reports",
|
||||
"description": "Server Reports",
|
||||
"version": "0.1.5",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"engines": {
|
||||
"vscode": "^1.26.0",
|
||||
"azdata": "*"
|
||||
},
|
||||
"icon": "images/sqlserver.png",
|
||||
"license": "SEE LICENSE IN LICENSE.txt",
|
||||
"repository": "https://github.com/Microsoft/azuredatastudio",
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"main": "./out/src/extension",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "tempdb.startEvent",
|
||||
"title": "Start",
|
||||
"icon": {
|
||||
"light": "./out/src/media/launch.svg",
|
||||
"dark": "./out/src/media/launch_inverse.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "tempdb.stopEvent",
|
||||
"title": "Stop",
|
||||
"icon": {
|
||||
"light": "./out/src/media/blocker.svg",
|
||||
"dark": "./out/src/media/blocker_inverse.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "tempdb.contention",
|
||||
"title": "Contention Help for Tempdb",
|
||||
"icon": {
|
||||
"light": "./out/src/media/documentation.svg",
|
||||
"dark": "./out/src/media/documentation_inverse.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "tempdb.pauseEvent",
|
||||
"title": "Pause",
|
||||
"icon": {
|
||||
"light": "./out/src/media/insights.svg",
|
||||
"dark": "./out/src/media/insights_inverse.svg"
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration": [],
|
||||
"views": {},
|
||||
"menus": {},
|
||||
"dashboard.tabs": [
|
||||
{
|
||||
"id": "Server-Reports",
|
||||
"title": "Server Reports",
|
||||
"description": "This extension shows useful reports for a server.",
|
||||
"container": {
|
||||
"nav-section": [
|
||||
{
|
||||
"id": "server-reports-monitoring",
|
||||
"title": "Monitor",
|
||||
"icon": {
|
||||
"light": "./out/src/media/monitor.svg",
|
||||
"dark": "./out/src/media/monitor_inverse.svg"
|
||||
},
|
||||
"container": {
|
||||
"server-reports-monitoring-container": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "server-reports-performance",
|
||||
"title": "Performance",
|
||||
"icon": {
|
||||
"light": "./out/src/media/performance.svg",
|
||||
"dark": "./out/src/media/performance_inverse.svg"
|
||||
},
|
||||
"container": {
|
||||
"server-reports-performance-container": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "server-reports-tempdb",
|
||||
"title": "TempDB",
|
||||
"container": {
|
||||
"server-reports-tempdb-container": {}
|
||||
},
|
||||
"icon": {
|
||||
"light": "./out/src/media/tempdb.svg",
|
||||
"dark": "./out/src/media/tempdb_inverse.svg"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"dashboard.insights": [
|
||||
{
|
||||
"id": "extension-dbspace-usage",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"horizontalBar": {
|
||||
"dataDirection": "vertical",
|
||||
"dataType": "number",
|
||||
"legendPosition": "top",
|
||||
"labelFirstColumn": false,
|
||||
"columnsAsLabels": true
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/all_db_space_used.sql"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "extension-cpu-utilization",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"timeSeries": {
|
||||
"dataDirection": "horizontal",
|
||||
"dataType": "point",
|
||||
"legendPosition": "top",
|
||||
"labelFirstColumn": false,
|
||||
"columnsAsLabels": false
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/cpumetric.sql"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "extension-backup-growth-trend",
|
||||
"details": "Abbie wants it",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"timeSeries": {
|
||||
"dataDirection": "horizontal",
|
||||
"dataType": "point",
|
||||
"legendPosition": "none",
|
||||
"labelFirstColumn": false,
|
||||
"columnsAsLabels": false
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/backup_size_trend.sql"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "extension-wait-counts-by-Paul-Randal",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"horizontalBar": {
|
||||
"dataDirection": "vertical",
|
||||
"dataType": "number",
|
||||
"legendPosition": "none",
|
||||
"labelFirstColumn": false,
|
||||
"columnsAsLabels": true
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/waits_paul_randal.sql",
|
||||
"details": {
|
||||
"queryFile": "./out/src/sql/waits_detail_paul_randal.sql",
|
||||
"label": {
|
||||
"column": "WaitType",
|
||||
"state": []
|
||||
},
|
||||
"value": "Percentage"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "extension-wait-resource-statistics",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"bar": {
|
||||
"dataDirection": "horizontal",
|
||||
"dataType": "number",
|
||||
"legendPosition": "none",
|
||||
"labelFirstColumn": false,
|
||||
"columnsAsLabels": true
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/wait_resources.sql",
|
||||
"details": {
|
||||
"queryFile": "./out/src/sql/wait_resources.sql",
|
||||
"label": {
|
||||
"column": "WaitType",
|
||||
"state": []
|
||||
},
|
||||
"value": "Percentage"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "extension-dbbuffer-usage",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"horizontalBar": {
|
||||
"dataDirection": "vertical",
|
||||
"dataType": "number",
|
||||
"legendPosition": "top",
|
||||
"labelFirstColumn": false,
|
||||
"columnsAsLabels": true
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/memorybydb.sql"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "type-of-contention",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"bar": {
|
||||
"dataDirection": "vertical",
|
||||
"columnsAsLabels": true,
|
||||
"labelFirstColumn": false,
|
||||
"legendPosition": "none"
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/typeofContentions.sql",
|
||||
"autoRefreshInterval": 0.05
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "metadata-contention",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"bar": {
|
||||
"dataDirection": "vertical",
|
||||
"columnsAsLabels": true,
|
||||
"labelFirstColumn": false,
|
||||
"legendPosition": "none",
|
||||
"xAxisLabel": "Object Ids for System Tables"
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/metadataContention.sql",
|
||||
"autoRefreshInterval": 0.05
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "allocation-contention",
|
||||
"contrib": {
|
||||
"type": {
|
||||
"bar": {
|
||||
"dataDirection": "vertical",
|
||||
"columnsAsLabels": true,
|
||||
"labelFirstColumn": false,
|
||||
"legendPosition": "none",
|
||||
"xAxisLabel": "Page Types"
|
||||
}
|
||||
},
|
||||
"queryFile": "./out/src/sql/allocationContention.sql",
|
||||
"autoRefreshInterval": 0.05
|
||||
}
|
||||
}
|
||||
],
|
||||
"dashboard.containers": [
|
||||
{
|
||||
"id": "server-reports-monitoring-container",
|
||||
"container": {
|
||||
"widgets-container": [
|
||||
{
|
||||
"name": "Top 10 DB Space Usage",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 2
|
||||
},
|
||||
"widget": {
|
||||
"extension-dbspace-usage": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Top 10 DB Buffer Usage",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 2
|
||||
},
|
||||
"widget": {
|
||||
"extension-dbbuffer-usage": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "CPU Utilization",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 1
|
||||
},
|
||||
"widget": {
|
||||
"extension-cpu-utilization": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Backup Growth Trend",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 1
|
||||
},
|
||||
"widget": {
|
||||
"extension-backup-growth-trend": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "server-reports-performance-container",
|
||||
"container": {
|
||||
"widgets-container": [
|
||||
{
|
||||
"name": "Wait Counts by Paul Randal",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 2
|
||||
},
|
||||
"widget": {
|
||||
"extension-wait-counts-by-Paul-Randal": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "server-reports-tempdb-container",
|
||||
"container": {
|
||||
"widgets-container": [
|
||||
{
|
||||
"name": "Tasks",
|
||||
"widget": {
|
||||
"tasks-widget": [
|
||||
"tempdb.startEvent",
|
||||
"tempdb.contention",
|
||||
"tempdb.pauseEvent",
|
||||
"tempdb.stopEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Overall Contention",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 1
|
||||
},
|
||||
"widget": {
|
||||
"type-of-contention": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Metadata Contention",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 1
|
||||
},
|
||||
"widget": {
|
||||
"metadata-contention": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Allocation Contention",
|
||||
"gridItemConfig": {
|
||||
"sizex": 2,
|
||||
"sizey": 1
|
||||
},
|
||||
"widget": {
|
||||
"allocation-contention": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"snippets": []
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp build",
|
||||
"compile": "gulp compile",
|
||||
"watch": "gulp watch",
|
||||
"postinstall": "node ./node_modules/vscode/bin/install"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs": "0.0.1-security",
|
||||
"fs-extra": "^8.1.0",
|
||||
"generator-sqlops": "^0.10.4",
|
||||
"handlebars": "^4.1.2",
|
||||
"openurl": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"child-process-promise": "^2.2.1",
|
||||
"del": "^3.0.0",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-color": "0.0.1",
|
||||
"gulp-sourcemaps": "^2.6.4",
|
||||
"gulp-tslint": "^6.0.2",
|
||||
"gulp-typescript": "^3.2.4",
|
||||
"should": "^13.2.1",
|
||||
"tslint": "^3.14.0",
|
||||
"typemoq": "^2.1.0",
|
||||
"typescript": "^2.9.2",
|
||||
"vsce": "1.36.2",
|
||||
"vscode": "^1.1.6"
|
||||
}
|
||||
}
|
||||
25
samples/serverReports/src/controllers/controllerBase.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. 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();
|
||||
}
|
||||
}
|
||||
|
||||
64
samples/serverReports/src/controllers/mainController.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as azdata from 'azdata';
|
||||
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> {
|
||||
azdata.tasks.registerTask("tempdb.startEvent", e => this.onExecute(e, 'startEvent.sql'));
|
||||
azdata.tasks.registerTask("tempdb.stopEvent", e => this.onExecute(e, 'stopEvent.sql'));
|
||||
azdata.tasks.registerTask("tempdb.contention", () => this.openurl('https://aka.ms/tempdbblog'));
|
||||
azdata.tasks.registerTask("tempdb.pauseEvent", e => this.stopAutoRefresh(e));
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
private openurl(link: string): void {
|
||||
openurl.open(link);
|
||||
}
|
||||
|
||||
private onExecute(connection: azdata.IConnectionProfile, fileName: string): void {
|
||||
//Command to start/stop autorefresh and run the query
|
||||
vscode.commands.executeCommand('azdata.widget.setAutoRefreshState', 'type-of-contention', connection.id, true);
|
||||
vscode.commands.executeCommand('azdata.widget.setAutoRefreshState', 'metadata-contention', connection.id, true);
|
||||
vscode.commands.executeCommand('azdata.widget.setAutoRefreshState', 'allocation-contention', connection.id, true);
|
||||
let sqlContent = fs.readFileSync(path.join(__dirname, '..', 'sql', fileName)).toString();
|
||||
vscode.workspace.openTextDocument({ language: 'sql', content: sqlContent }).then(doc => {
|
||||
vscode.window.showTextDocument(doc, vscode.ViewColumn.Active, false).then(() => {
|
||||
let filePath = doc.uri.toString();
|
||||
azdata.queryeditor.connect(filePath, connection.id).then(() => azdata.queryeditor.runQuery(filePath, undefined, false));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private stopAutoRefresh(connection: azdata.IConnectionProfile) {
|
||||
vscode.commands.executeCommand('azdata.widget.setAutoRefreshState', 'type-of-contention', connection.id, false);
|
||||
vscode.commands.executeCommand('azdata.widget.setAutoRefreshState', 'metadata-contention', connection.id, false);
|
||||
vscode.commands.executeCommand('azdata.widget.setAutoRefreshState', 'allocation-contention', connection.id, false);
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,33 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext): void {
|
||||
// No-op
|
||||
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 {
|
||||
// No-op
|
||||
for (let controller of controllers) {
|
||||
controller.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
// TODO: localize!
|
||||
export const msgErrorLoadingTab = 'An error occurred while loading the tab.';
|
||||
|
||||
1
samples/serverReports/src/media/blocker.svg
Normal 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:#212121;}</style></defs><title>blocker</title><polygon class="cls-1" points="0.99 3.99 -0.01 3.99 -0.01 0.03 3.98 0.03 3.98 1.03 0.99 1.03 0.99 3.99"/><polygon class="cls-1" points="16.01 3.99 15.01 3.99 15.01 1.03 12.02 1.03 12.02 0.03 16.01 0.03 16.01 3.99"/><polygon class="cls-1" points="16.01 15.97 12.02 15.97 12.02 14.97 15.01 14.97 15.01 12.01 16.01 12.01 16.01 15.97"/><polygon class="cls-1" points="4 15.97 0.01 15.97 0.01 12.01 1.01 12.01 1.01 14.97 4 14.97 4 15.97"/><path class="cls-1" d="M8.41,3.18A4.82,4.82,0,1,0,13.23,8,4.83,4.83,0,0,0,8.41,3.18Zm0,.74A4.08,4.08,0,0,1,12.49,8a4,4,0,0,1-.85,2.47L5.69,5A4,4,0,0,1,8.41,3.93Zm0,8.15A4.08,4.08,0,0,1,4.34,8a4,4,0,0,1,.85-2.47L11.14,11A4,4,0,0,1,8.41,12.07Z"/></svg>
|
||||
|
After Width: | Height: | Size: 847 B |
1
samples/serverReports/src/media/blocker_inverse.svg
Normal 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>blocker_inverse</title><polygon class="cls-1" points="0.99 3.99 -0.01 3.99 -0.01 0.03 3.98 0.03 3.98 1.03 0.99 1.03 0.99 3.99"/><polygon class="cls-1" points="16.01 3.99 15.01 3.99 15.01 1.03 12.02 1.03 12.02 0.03 16.01 0.03 16.01 3.99"/><polygon class="cls-1" points="16.01 15.97 12.02 15.97 12.02 14.97 15.01 14.97 15.01 12.01 16.01 12.01 16.01 15.97"/><polygon class="cls-1" points="4 15.97 0.01 15.97 0.01 12.01 1.01 12.01 1.01 14.97 4 14.97 4 15.97"/><path class="cls-1" d="M8.41,3.18A4.82,4.82,0,1,0,13.23,8,4.83,4.83,0,0,0,8.41,3.18Zm0,.74A4.08,4.08,0,0,1,12.49,8a4,4,0,0,1-.85,2.47L5.69,5A4,4,0,0,1,8.41,3.93Zm0,8.15A4.08,4.08,0,0,1,4.34,8a4,4,0,0,1,.85-2.47L11.14,11A4,4,0,0,1,8.41,12.07Z"/></svg>
|
||||
|
After Width: | Height: | Size: 852 B |
1
samples/serverReports/src/media/documentation.svg
Normal 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:#212121;}</style></defs><title>documentation</title><path class="cls-1" d="M14,4.29V16H1V0H9.72ZM13,5H9V1H2V15H13ZM3,4H8V5H3ZM3,8H8V9H3Zm0,4H8v1H3ZM9,7h3v3H9Zm0,4h3v3H9Zm1-7H12.3L10,1.71Zm0,5h1V8H10Zm0,4h1V12H10Z"/></svg>
|
||||
|
After Width: | Height: | Size: 339 B |
@@ -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>documentation_1</title><path class="cls-1" d="M14,4.29V16H1V0H9.72ZM13,5H9V1H2V15H13ZM3,4H8V5H3ZM3,8H8V9H3Zm0,4H8v1H3ZM9,7h3v3H9Zm0,4h3v3H9Zm1-7H12.3L10,1.71Zm0,5h1V8H10Zm0,4h1V12H10Z"/></svg>
|
||||
|
After Width: | Height: | Size: 338 B |
1
samples/serverReports/src/media/insights.svg
Normal 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:#212121;}</style></defs><title>insights</title><path class="cls-1" d="M15,4V8H14V5.71L9.49,10.2l-2-2L2,13.71V14H15v1H1V1H2V12.29L7.49,6.8l2,2L13.28,5H11V4Z"/></svg>
|
||||
|
After Width: | Height: | Size: 282 B |
1
samples/serverReports/src/media/insights_inverse.svg
Normal 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>insights_inverse</title><path class="cls-1" d="M15,4V8H14V5.71L9.49,10.2l-2-2L2,13.71V14H15v1H1V1H2V12.29L7.49,6.8l2,2L13.28,5H11V4Z"/></svg>
|
||||
|
After Width: | Height: | Size: 287 B |
1
samples/serverReports/src/media/launch.svg
Normal 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>launch</title><path d="M12.8,8.4l1.07-1.07v6.4H0V4.13H10.67L9.6,5.2H1.07v7.47H12.8Zm0-6.4H16V5.2H14.93V3.82l-3.8,3.8-.76-.76,3.8-3.8H12.8Z"/></svg>
|
||||
|
After Width: | Height: | Size: 247 B |
1
samples/serverReports/src/media/launch_inverse.svg
Normal 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>launch_inverse</title><path class="cls-1" d="M12.8,8.4l1.07-1.07v6.4H0V4.13H10.67L9.6,5.2H1.07v7.47H12.8Zm0-6.4H16V5.2H14.93V3.82l-3.8,3.8-.76-.76,3.8-3.8H12.8Z"/></svg>
|
||||
|
After Width: | Height: | Size: 315 B |
9
samples/serverReports/src/media/tempdb.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>TemporaryDatabase</title>
|
||||
<g>
|
||||
<path d="M3.086,3.758a1.565,1.565,0,0,0,.492.445,3.788,3.788,0,0,0,.719.336,6.428,6.428,0,0,0,.848.234q.449.095.878.153t.817.082c.258.015.477.023.66.023s.4-.008.66-.023.53-.043.817-.082.579-.09.878-.153a6.428,6.428,0,0,0,.848-.234,3.842,3.842,0,0,0,.715-.332,1.6,1.6,0,0,0,.5-.449.555.555,0,0,0,.063-.11A.3.3,0,0,0,12,3.531a.462.462,0,0,0-.133-.312,1.7,1.7,0,0,0-.32-.274,3.616,3.616,0,0,0-.383-.222c-.13-.065-.234-.114-.312-.145a6.1,6.1,0,0,0-.79-.254q-.421-.1-.859-.172t-.871-.093c-.289-.018-.566-.028-.832-.028s-.543.01-.832.028-.58.049-.871.093-.578.1-.859.172a6.047,6.047,0,0,0-.79.254c-.078.031-.182.08-.312.145a3.616,3.616,0,0,0-.383.222,1.673,1.673,0,0,0-.32.274A.462.462,0,0,0,3,3.531a.3.3,0,0,0,.023.117A.555.555,0,0,0,3.086,3.758Z" fill="none"/>
|
||||
<path d="M7.435,14.03c-.282,0-.6-.017-.951-.046a10.214,10.214,0,0,1-1.148-.16,7.424,7.424,0,0,1-1.106-.3,3.184,3.184,0,0,1-.894-.481,1.519,1.519,0,0,1-.223-.219A.436.436,0,0,1,3,12.531V5.016A5.236,5.236,0,0,0,4.023,5.5a8.163,8.163,0,0,0,1.149.312,10.5,10.5,0,0,0,1.191.168c.4.035.778.051,1.137.051s.738-.016,1.137-.051a10.368,10.368,0,0,0,1.187-.168A8.39,8.39,0,0,0,10.973,5.5,5.218,5.218,0,0,0,12,5.016V7a5.092,5.092,0,0,1,1,.1V3.531a1.333,1.333,0,0,0-.152-.625,1.97,1.97,0,0,0-.4-.515,3.518,3.518,0,0,0-1.039-.664,7.269,7.269,0,0,0-1.3-.418,10.78,10.78,0,0,0-1.367-.215c-.456-.041-.871-.063-1.246-.063-.245,0-.511.01-.8.028s-.583.048-.891.089-.617.1-.929.164a7.689,7.689,0,0,0-.9.254,5.562,5.562,0,0,0-.8.356,2.788,2.788,0,0,0-.637.469,2.164,2.164,0,0,0-.395.511A1.3,1.3,0,0,0,2,3.531v9a1.316,1.316,0,0,0,.176.676,2.049,2.049,0,0,0,.465.543,3.278,3.278,0,0,0,.656.426,6.65,6.65,0,0,0,.75.32,7.384,7.384,0,0,0,.75.227c.245.06.463.1.656.136a11.923,11.923,0,0,0,2.047.172c.177,0,.354-.005.532-.013A5.006,5.006,0,0,1,7.435,14.03ZM3.133,3.219a1.673,1.673,0,0,1,.32-.274,3.616,3.616,0,0,1,.383-.222c.13-.065.234-.114.312-.145a6.047,6.047,0,0,1,.79-.254q.422-.1.859-.172c.291-.044.582-.075.871-.093s.566-.028.832-.028.543.01.832.028.579.049.871.093.578.1.859.172a6.1,6.1,0,0,1,.79.254c.078.031.182.08.312.145a3.616,3.616,0,0,1,.383.222,1.7,1.7,0,0,1,.32.274A.462.462,0,0,1,12,3.531a.3.3,0,0,1-.023.117.555.555,0,0,1-.063.11,1.6,1.6,0,0,1-.5.449,3.842,3.842,0,0,1-.715.332,6.428,6.428,0,0,1-.848.234q-.449.095-.878.153t-.817.082q-.387.022-.66.023c-.183,0-.4-.008-.66-.023s-.53-.043-.817-.082-.579-.09-.878-.153A6.428,6.428,0,0,1,4.3,4.539,3.788,3.788,0,0,1,3.578,4.2a1.565,1.565,0,0,1-.492-.445.555.555,0,0,1-.063-.11A.3.3,0,0,1,3,3.531.462.462,0,0,1,3.133,3.219Z"/>
|
||||
<polygon points="12 10 11 10 11 13 13.5 13 13.5 12 12 12 12 10"/>
|
||||
<path d="M15.688,10.441a3.99,3.99,0,0,0-2.129-2.129,4.051,4.051,0,0,0-3.118,0,3.99,3.99,0,0,0-2.129,2.129,4.051,4.051,0,0,0,0,3.118,3.99,3.99,0,0,0,2.129,2.129,4.051,4.051,0,0,0,3.118,0,3.99,3.99,0,0,0,2.129-2.129,4.051,4.051,0,0,0,0-3.118Zm-.922,2.727a3.029,3.029,0,0,1-1.6,1.6,3.022,3.022,0,0,1-2.332,0,3.04,3.04,0,0,1-1.6-1.6,3.022,3.022,0,0,1,0-2.332,3.029,3.029,0,0,1,1.6-1.6,3.022,3.022,0,0,1,2.332,0,3.019,3.019,0,0,1,1.6,1.6,3.022,3.022,0,0,1,0,2.332Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
9
samples/serverReports/src/media/tempdb_inverse.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>TemporaryDatabase_Inverse</title>
|
||||
<g>
|
||||
<path d="M3.086,3.758a1.565,1.565,0,0,0,.492.445,3.788,3.788,0,0,0,.719.336,6.428,6.428,0,0,0,.848.234q.449.095.878.153t.817.082c.258.015.477.023.66.023s.4-.008.66-.023.53-.043.817-.082.579-.09.878-.153a6.428,6.428,0,0,0,.848-.234,3.842,3.842,0,0,0,.715-.332,1.6,1.6,0,0,0,.5-.449.555.555,0,0,0,.063-.11A.3.3,0,0,0,12,3.531a.462.462,0,0,0-.133-.312,1.7,1.7,0,0,0-.32-.274,3.616,3.616,0,0,0-.383-.222c-.13-.065-.234-.114-.312-.145a6.1,6.1,0,0,0-.79-.254q-.421-.1-.859-.172t-.871-.093c-.289-.018-.566-.028-.832-.028s-.543.01-.832.028-.58.049-.871.093-.578.1-.859.172a6.047,6.047,0,0,0-.79.254c-.078.031-.182.08-.312.145a3.616,3.616,0,0,0-.383.222,1.673,1.673,0,0,0-.32.274A.462.462,0,0,0,3,3.531a.3.3,0,0,0,.023.117A.555.555,0,0,0,3.086,3.758Z" fill="#fff"/>
|
||||
<path d="M7.435,14.03c-.282,0-.6-.017-.951-.046a10.214,10.214,0,0,1-1.148-.16,7.424,7.424,0,0,1-1.106-.3,3.184,3.184,0,0,1-.894-.481,1.519,1.519,0,0,1-.223-.219A.436.436,0,0,1,3,12.531V5.016A5.236,5.236,0,0,0,4.023,5.5a8.163,8.163,0,0,0,1.149.312,10.5,10.5,0,0,0,1.191.168c.4.035.778.051,1.137.051s.738-.016,1.137-.051a10.368,10.368,0,0,0,1.187-.168A8.39,8.39,0,0,0,10.973,5.5,5.218,5.218,0,0,0,12,5.016V7a5.092,5.092,0,0,1,1,.1V3.531a1.333,1.333,0,0,0-.152-.625,1.97,1.97,0,0,0-.4-.515,3.518,3.518,0,0,0-1.039-.664,7.269,7.269,0,0,0-1.3-.418,10.78,10.78,0,0,0-1.367-.215c-.456-.041-.871-.063-1.246-.063-.245,0-.511.01-.8.028s-.583.048-.891.089-.617.1-.929.164a7.689,7.689,0,0,0-.9.254,5.562,5.562,0,0,0-.8.356,2.788,2.788,0,0,0-.637.469,2.164,2.164,0,0,0-.395.511A1.3,1.3,0,0,0,2,3.531v9a1.316,1.316,0,0,0,.176.676,2.049,2.049,0,0,0,.465.543,3.278,3.278,0,0,0,.656.426,6.65,6.65,0,0,0,.75.32,7.384,7.384,0,0,0,.75.227c.245.06.463.1.656.136a11.923,11.923,0,0,0,2.047.172c.177,0,.354-.005.532-.013A5.006,5.006,0,0,1,7.435,14.03ZM3.133,3.219a1.673,1.673,0,0,1,.32-.274,3.616,3.616,0,0,1,.383-.222c.13-.065.234-.114.312-.145a6.047,6.047,0,0,1,.79-.254q.422-.1.859-.172c.291-.044.582-.075.871-.093s.566-.028.832-.028.543.01.832.028.579.049.871.093.578.1.859.172a6.1,6.1,0,0,1,.79.254c.078.031.182.08.312.145a3.616,3.616,0,0,1,.383.222,1.7,1.7,0,0,1,.32.274A.462.462,0,0,1,12,3.531a.3.3,0,0,1-.023.117.555.555,0,0,1-.063.11,1.6,1.6,0,0,1-.5.449,3.842,3.842,0,0,1-.715.332,6.428,6.428,0,0,1-.848.234q-.449.095-.878.153t-.817.082q-.387.022-.66.023c-.183,0-.4-.008-.66-.023s-.53-.043-.817-.082-.579-.09-.878-.153A6.428,6.428,0,0,1,4.3,4.539,3.788,3.788,0,0,1,3.578,4.2a1.565,1.565,0,0,1-.492-.445.555.555,0,0,1-.063-.11A.3.3,0,0,1,3,3.531.462.462,0,0,1,3.133,3.219Z" fill="#fff"/>
|
||||
<polygon points="12 10 11 10 11 13 13.5 13 13.5 12 12 12 12 10" fill="#fff"/>
|
||||
<path d="M15.688,10.441a3.99,3.99,0,0,0-2.129-2.129,4.051,4.051,0,0,0-3.118,0,3.99,3.99,0,0,0-2.129,2.129,4.051,4.051,0,0,0,0,3.118,3.99,3.99,0,0,0,2.129,2.129,4.051,4.051,0,0,0,3.118,0,3.99,3.99,0,0,0,2.129-2.129,4.051,4.051,0,0,0,0-3.118Zm-.922,2.727a3.029,3.029,0,0,1-1.6,1.6,3.022,3.022,0,0,1-2.332,0,3.04,3.04,0,0,1-1.6-1.6,3.022,3.022,0,0,1,0-2.332,3.029,3.029,0,0,1,1.6-1.6,3.022,3.022,0,0,1,2.332,0,3.019,3.019,0,0,1,1.6,1.6,3.022,3.022,0,0,1,0,2.332Z" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
34
samples/serverReports/src/resources/templateTab.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<!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>
|
||||
19
samples/serverReports/src/sql/allocationContention.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
--SQL script to grab allocation contention from histogram
|
||||
Use tempdb
|
||||
DECLARE @target_data XML;
|
||||
SELECT @target_data = CAST(t.target_data AS XML)
|
||||
FROM sys.dm_xe_sessions AS s
|
||||
JOIN sys.dm_xe_session_targets AS t
|
||||
ON t.event_session_address = s.address
|
||||
WHERE s.name = N'PageContention' and t.target_name = N'histogram';
|
||||
|
||||
with wait_stats as
|
||||
(
|
||||
SELECT
|
||||
n.value('(value)[1]','bigint') AS id,
|
||||
n.value('(@count)[1]', 'bigint') AS [Count]
|
||||
FROM @target_data.nodes('//HistogramTarget/Slot') AS q(n)
|
||||
)
|
||||
|
||||
SELECT [dbo].[mapPageType](wait_stats.id), wait_stats.Count
|
||||
FROM wait_stats
|
||||
22
samples/serverReports/src/sql/metadataContention.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
--SQL script to grab metadata contention from histogram
|
||||
Use tempdb
|
||||
DECLARE @target_data XML;
|
||||
SELECT @target_data = CAST(t.target_data AS XML)
|
||||
FROM sys.dm_xe_sessions AS s
|
||||
JOIN sys.dm_xe_session_targets AS t
|
||||
ON t.event_session_address = s.address
|
||||
WHERE s.name = N'ObjectContention' and t.target_name = N'histogram';
|
||||
|
||||
with wait_stats as
|
||||
(
|
||||
SELECT
|
||||
n.value('(value)[1]','bigint') AS alloc_unit_id,
|
||||
n.value('(@count)[1]', 'bigint') AS [Count]
|
||||
FROM @target_data.nodes('//HistogramTarget/Slot') AS q(n)
|
||||
)
|
||||
|
||||
SELECT objects.id, SUM(objects.count) as [Count] FROM
|
||||
(SELECT [dbo].[isSystemTable](wait_stats.alloc_unit_id) AS id, wait_stats.Count AS [count]
|
||||
FROM wait_stats
|
||||
WHERE [dbo].[isSystemTable](wait_stats.alloc_unit_id) not in (0, 99)) AS objects
|
||||
GROUP BY objects.id
|
||||
80
samples/serverReports/src/sql/startEvent.sql
Normal file
@@ -0,0 +1,80 @@
|
||||
--Starts the XEvents sessions and creates the functions needed to find object id and give name to the page types
|
||||
use tempdb
|
||||
|
||||
BEGIN TRY
|
||||
IF NOT EXISTS (SELECT * FROM sys.dm_xe_sessions WHERE name = 'PageContention')
|
||||
BEGIN
|
||||
CREATE EVENT SESSION [PageContention] ON SERVER
|
||||
ADD EVENT latch_suspend_end(
|
||||
WHERE class = 28
|
||||
AND (page_type_id = 8
|
||||
OR page_type_id = 9
|
||||
OR page_type_id = 11))
|
||||
ADD TARGET package0.histogram(SET slots=16, filtering_event_name=N'latch_suspend_end', source=N'page_type_id', source_type=(0))
|
||||
ALTER EVENT SESSION [PageContention] ON SERVER
|
||||
STATE = START
|
||||
END
|
||||
IF NOT EXISTS (SELECT * FROM sys.dm_xe_sessions WHERE name = 'ObjectContention')
|
||||
BEGIN
|
||||
CREATE EVENT SESSION [ObjectContention] ON SERVER
|
||||
ADD EVENT latch_suspend_end(
|
||||
WHERE class = 28
|
||||
AND database_id = 2)
|
||||
ADD TARGET package0.histogram(SET slots=256, filtering_event_name=N'latch_suspend_end', source=N'page_alloc_unit_id', source_type=(0))
|
||||
ALTER EVENT SESSION [ObjectContention] ON SERVER
|
||||
STATE = START
|
||||
END
|
||||
END TRY
|
||||
BEGIN CATCH
|
||||
PRINT 'XEvent fields not supported'
|
||||
END CATCH
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[isSystemTable]', N'FN') IS NOT NULL
|
||||
DROP FUNCTION [dbo].[isSystemTable]
|
||||
GO
|
||||
|
||||
CREATE FUNCTION [dbo].[isSystemTable] (@alloc bigint)
|
||||
RETURNS bigint
|
||||
|
||||
AS BEGIN
|
||||
|
||||
DECLARE @index BIGINT;
|
||||
DECLARE @objId BIGINT;
|
||||
|
||||
SELECT @index =
|
||||
CONVERT (BIGINT,
|
||||
CONVERT (FLOAT, @alloc)
|
||||
* (1 / POWER (2.0, 48))
|
||||
);
|
||||
SELECT @objId =
|
||||
CONVERT (BIGINT,
|
||||
CONVERT (FLOAT, @alloc - (@index * CONVERT (BIGINT, POWER (2.0, 48))))
|
||||
* (1 / POWER (2.0, 16))
|
||||
);
|
||||
|
||||
IF (@objId > 0 AND @objId <= 100 AND @index <= 255)
|
||||
return @objId
|
||||
|
||||
return 0
|
||||
|
||||
END
|
||||
GO
|
||||
|
||||
IF OBJECT_ID(N'[dbo].[mapPageType]', N'FN') IS NOT NULL
|
||||
DROP FUNCTION [dbo].[mapPageType]
|
||||
GO
|
||||
|
||||
CREATE FUNCTION [dbo].[mapPageType] (@pageTypeId bigint)
|
||||
RETURNS varchar(20)
|
||||
|
||||
AS BEGIN
|
||||
IF @pageTypeId = 8
|
||||
return 'GAM_PAGE'
|
||||
ELSE IF @pageTypeId = 9
|
||||
return 'SGAM_PAGE'
|
||||
ELSE IF @pageTypeId = 11
|
||||
return 'PFS_PAGE'
|
||||
return ''
|
||||
END
|
||||
GO
|
||||
3
samples/serverReports/src/sql/stopEvent.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
--Stops the XEvent Sessions
|
||||
DROP EVENT SESSION [PageContention] ON SERVER
|
||||
DROP EVENT SESSION [ObjectContention] ON SERVER
|
||||
33
samples/serverReports/src/sql/typeofContentions.sql
Normal file
@@ -0,0 +1,33 @@
|
||||
--SQL script to grab all contention
|
||||
Use tempdb
|
||||
DECLARE @pc XML;
|
||||
DECLARE @obj XML;
|
||||
|
||||
SELECT @pc = CAST(t.target_data AS XML)
|
||||
FROM sys.dm_xe_sessions AS s
|
||||
JOIN sys.dm_xe_session_targets AS t
|
||||
ON t.event_session_address = s.address
|
||||
WHERE s.name = N'PageContention' and t.target_name = N'histogram';
|
||||
|
||||
SELECT @obj = CAST(t.target_data AS XML)
|
||||
FROM sys.dm_xe_sessions AS s
|
||||
JOIN sys.dm_xe_session_targets AS t
|
||||
ON t.event_session_address = s.address
|
||||
WHERE s.name = N'ObjectContention' and t.target_name = N'histogram';
|
||||
|
||||
SELECT 'Metadata Contention' AS wait_type, SUM(obj.count) AS [Count]
|
||||
FROM (
|
||||
SELECT
|
||||
n.value('(value)[1]','bigint') AS alloc_unit_id,
|
||||
n.value('(@count)[1]', 'bigint') AS [count]
|
||||
FROM @obj.nodes('//HistogramTarget/Slot') AS q(n)
|
||||
) obj
|
||||
WHERE [dbo].[isSystemTable](obj.alloc_unit_id) not in (0, 99)
|
||||
UNION
|
||||
SELECT 'Allocation Contention' AS wait_type, SUM(pc.count) AS [Count]
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
n.value('(@count)[1]', 'bigint') AS [count]
|
||||
FROM @pc.nodes('//HistogramTarget/Slot') AS q(n)
|
||||
) pc
|
||||
95
samples/serverReports/src/sql/wait_resources.sql
Normal file
@@ -0,0 +1,95 @@
|
||||
WITH [Waits] AS
|
||||
(
|
||||
SELECT wait_type, resource_description, count(resource_description) AS RESOURCE_USE, COUNT(*) AS TOTAL FROM sys.dm_os_waiting_tasks
|
||||
WHERE [wait_type] NOT IN (
|
||||
-- These wait types are almost 100% never a problem and so they are
|
||||
-- filtered out to avoid them skewing the results. Click on the URL
|
||||
-- for more information.
|
||||
N'BROKER_EVENTHANDLER', -- https://www.sqlskills.com/help/waits/BROKER_EVENTHANDLER
|
||||
N'BROKER_RECEIVE_WAITFOR', -- https://www.sqlskills.com/help/waits/BROKER_RECEIVE_WAITFOR
|
||||
N'BROKER_TASK_STOP', -- https://www.sqlskills.com/help/waits/BROKER_TASK_STOP
|
||||
N'BROKER_TO_FLUSH', -- https://www.sqlskills.com/help/waits/BROKER_TO_FLUSH
|
||||
N'BROKER_TRANSMITTER', -- https://www.sqlskills.com/help/waits/BROKER_TRANSMITTER
|
||||
N'CHECKPOINT_QUEUE', -- https://www.sqlskills.com/help/waits/CHECKPOINT_QUEUE
|
||||
N'CHKPT', -- https://www.sqlskills.com/help/waits/CHKPT
|
||||
N'CLR_AUTO_EVENT', -- https://www.sqlskills.com/help/waits/CLR_AUTO_EVENT
|
||||
N'CLR_MANUAL_EVENT', -- https://www.sqlskills.com/help/waits/CLR_MANUAL_EVENT
|
||||
N'CLR_SEMAPHORE', -- https://www.sqlskills.com/help/waits/CLR_SEMAPHORE
|
||||
N'CXCONSUMER', -- https://www.sqlskills.com/help/waits/CXCONSUMER
|
||||
|
||||
-- Maybe comment these four out if you have mirroring issues
|
||||
N'DBMIRROR_DBM_EVENT', -- https://www.sqlskills.com/help/waits/DBMIRROR_DBM_EVENT
|
||||
N'DBMIRROR_EVENTS_QUEUE', -- https://www.sqlskills.com/help/waits/DBMIRROR_EVENTS_QUEUE
|
||||
N'DBMIRROR_WORKER_QUEUE', -- https://www.sqlskills.com/help/waits/DBMIRROR_WORKER_QUEUE
|
||||
N'DBMIRRORING_CMD', -- https://www.sqlskills.com/help/waits/DBMIRRORING_CMD
|
||||
|
||||
N'DIRTY_PAGE_POLL', -- https://www.sqlskills.com/help/waits/DIRTY_PAGE_POLL
|
||||
N'DISPATCHER_QUEUE_SEMAPHORE', -- https://www.sqlskills.com/help/waits/DISPATCHER_QUEUE_SEMAPHORE
|
||||
N'EXECSYNC', -- https://www.sqlskills.com/help/waits/EXECSYNC
|
||||
N'FSAGENT', -- https://www.sqlskills.com/help/waits/FSAGENT
|
||||
N'FT_IFTS_SCHEDULER_IDLE_WAIT', -- https://www.sqlskills.com/help/waits/FT_IFTS_SCHEDULER_IDLE_WAIT
|
||||
N'FT_IFTSHC_MUTEX', -- https://www.sqlskills.com/help/waits/FT_IFTSHC_MUTEX
|
||||
|
||||
-- Maybe comment these six out if you have AG issues
|
||||
N'HADR_CLUSAPI_CALL', -- https://www.sqlskills.com/help/waits/HADR_CLUSAPI_CALL
|
||||
N'HADR_FILESTREAM_IOMGR_IOCOMPLETION', -- https://www.sqlskills.com/help/waits/HADR_FILESTREAM_IOMGR_IOCOMPLETION
|
||||
N'HADR_LOGCAPTURE_WAIT', -- https://www.sqlskills.com/help/waits/HADR_LOGCAPTURE_WAIT
|
||||
N'HADR_NOTIFICATION_DEQUEUE', -- https://www.sqlskills.com/help/waits/HADR_NOTIFICATION_DEQUEUE
|
||||
N'HADR_TIMER_TASK', -- https://www.sqlskills.com/help/waits/HADR_TIMER_TASK
|
||||
N'HADR_WORK_QUEUE', -- https://www.sqlskills.com/help/waits/HADR_WORK_QUEUE
|
||||
|
||||
N'KSOURCE_WAKEUP', -- https://www.sqlskills.com/help/waits/KSOURCE_WAKEUP
|
||||
N'LAZYWRITER_SLEEP', -- https://www.sqlskills.com/help/waits/LAZYWRITER_SLEEP
|
||||
N'LOGMGR_QUEUE', -- https://www.sqlskills.com/help/waits/LOGMGR_QUEUE
|
||||
N'MEMORY_ALLOCATION_EXT', -- https://www.sqlskills.com/help/waits/MEMORY_ALLOCATION_EXT
|
||||
N'ONDEMAND_TASK_QUEUE', -- https://www.sqlskills.com/help/waits/ONDEMAND_TASK_QUEUE
|
||||
N'PARALLEL_REDO_DRAIN_WORKER', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_DRAIN_WORKER
|
||||
N'PARALLEL_REDO_LOG_CACHE', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_LOG_CACHE
|
||||
N'PARALLEL_REDO_TRAN_LIST', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_TRAN_LIST
|
||||
N'PARALLEL_REDO_WORKER_SYNC', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_WORKER_SYNC
|
||||
N'PARALLEL_REDO_WORKER_WAIT_WORK', -- https://www.sqlskills.com/help/waits/PARALLEL_REDO_WORKER_WAIT_WORK
|
||||
N'PREEMPTIVE_OS_FLUSHFILEBUFFERS', -- https://www.sqlskills.com/help/waits/PREEMPTIVE_OS_FLUSHFILEBUFFERS
|
||||
N'PREEMPTIVE_XE_GETTARGETSTATE', -- https://www.sqlskills.com/help/waits/PREEMPTIVE_XE_GETTARGETSTATE
|
||||
N'PWAIT_ALL_COMPONENTS_INITIALIZED', -- https://www.sqlskills.com/help/waits/PWAIT_ALL_COMPONENTS_INITIALIZED
|
||||
N'PWAIT_DIRECTLOGCONSUMER_GETNEXT', -- https://www.sqlskills.com/help/waits/PWAIT_DIRECTLOGCONSUMER_GETNEXT
|
||||
N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP', -- https://www.sqlskills.com/help/waits/QDS_PERSIST_TASK_MAIN_LOOP_SLEEP
|
||||
N'QDS_ASYNC_QUEUE', -- https://www.sqlskills.com/help/waits/QDS_ASYNC_QUEUE
|
||||
N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP',
|
||||
-- https://www.sqlskills.com/help/waits/QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP
|
||||
N'QDS_SHUTDOWN_QUEUE', -- https://www.sqlskills.com/help/waits/QDS_SHUTDOWN_QUEUE
|
||||
N'REDO_THREAD_PENDING_WORK', -- https://www.sqlskills.com/help/waits/REDO_THREAD_PENDING_WORK
|
||||
N'REQUEST_FOR_DEADLOCK_SEARCH', -- https://www.sqlskills.com/help/waits/REQUEST_FOR_DEADLOCK_SEARCH
|
||||
N'RESOURCE_QUEUE', -- https://www.sqlskills.com/help/waits/RESOURCE_QUEUE
|
||||
N'SERVER_IDLE_CHECK', -- https://www.sqlskills.com/help/waits/SERVER_IDLE_CHECK
|
||||
N'SLEEP_BPOOL_FLUSH', -- https://www.sqlskills.com/help/waits/SLEEP_BPOOL_FLUSH
|
||||
N'SLEEP_DBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_DBSTARTUP
|
||||
N'SLEEP_DCOMSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_DCOMSTARTUP
|
||||
N'SLEEP_MASTERDBREADY', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERDBREADY
|
||||
N'SLEEP_MASTERMDREADY', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERMDREADY
|
||||
N'SLEEP_MASTERUPGRADED', -- https://www.sqlskills.com/help/waits/SLEEP_MASTERUPGRADED
|
||||
N'SLEEP_MSDBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_MSDBSTARTUP
|
||||
N'SLEEP_SYSTEMTASK', -- https://www.sqlskills.com/help/waits/SLEEP_SYSTEMTASK
|
||||
N'SLEEP_TASK', -- https://www.sqlskills.com/help/waits/SLEEP_TASK
|
||||
N'SLEEP_TEMPDBSTARTUP', -- https://www.sqlskills.com/help/waits/SLEEP_TEMPDBSTARTUP
|
||||
N'SNI_HTTP_ACCEPT', -- https://www.sqlskills.com/help/waits/SNI_HTTP_ACCEPT
|
||||
N'SOS_WORK_DISPATCHER', -- https://www.sqlskills.com/help/waits/SOS_WORK_DISPATCHER
|
||||
N'SP_SERVER_DIAGNOSTICS_SLEEP', -- https://www.sqlskills.com/help/waits/SP_SERVER_DIAGNOSTICS_SLEEP
|
||||
N'SQLTRACE_BUFFER_FLUSH', -- https://www.sqlskills.com/help/waits/SQLTRACE_BUFFER_FLUSH
|
||||
N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP', -- https://www.sqlskills.com/help/waits/SQLTRACE_INCREMENTAL_FLUSH_SLEEP
|
||||
N'SQLTRACE_WAIT_ENTRIES', -- https://www.sqlskills.com/help/waits/SQLTRACE_WAIT_ENTRIES
|
||||
N'VDI_CLIENT_OTHER', -- https://www.sqlskills.com/help/waits/VDI_CLIENT_OTHER
|
||||
N'WAIT_FOR_RESULTS', -- https://www.sqlskills.com/help/waits/WAIT_FOR_RESULTS
|
||||
N'WAITFOR', -- https://www.sqlskills.com/help/waits/WAITFOR
|
||||
N'WAITFOR_TASKSHUTDOWN', -- https://www.sqlskills.com/help/waits/WAITFOR_TASKSHUTDOWN
|
||||
N'WAIT_XTP_RECOVERY', -- https://www.sqlskills.com/help/waits/WAIT_XTP_RECOVERY
|
||||
N'WAIT_XTP_HOST_WAIT', -- https://www.sqlskills.com/help/waits/WAIT_XTP_HOST_WAIT
|
||||
N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG', -- https://www.sqlskills.com/help/waits/WAIT_XTP_OFFLINE_CKPT_NEW_LOG
|
||||
N'WAIT_XTP_CKPT_CLOSE', -- https://www.sqlskills.com/help/waits/WAIT_XTP_CKPT_CLOSE
|
||||
N'XE_DISPATCHER_JOIN', -- https://www.sqlskills.com/help/waits/XE_DISPATCHER_JOIN
|
||||
N'XE_DISPATCHER_WAIT', -- https://www.sqlskills.com/help/waits/XE_DISPATCHER_WAIT
|
||||
N'XE_TIMER_EVENT' -- https://www.sqlskills.com/help/waits/XE_TIMER_EVENT
|
||||
)
|
||||
GROUP BY sys.dm_os_waiting_tasks.resource_description, wait_type
|
||||
)
|
||||
|
||||
SELECT [TASKS].[wait_type] AS [WaitType], [TASKS].[resource_description] as [Resource], 100.0 * [TASKS].[TOTAL] / SUM ([TASKS].[TOTAL]) OVER () AS [Percentage] FROM Waits AS TASKS GROUP BY [TASKS].[wait_type], [TASKS].[resource_description], [TASKS].[TOTAL]
|
||||
@@ -5,21 +5,42 @@
|
||||
|
||||
'use strict';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as handlebars from 'handlebars';
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,67 +18,67 @@ let tsProject = ts.createProject('tsconfig.json');
|
||||
|
||||
|
||||
// GULP TASKS //////////////////////////////////////////////////////////////
|
||||
gulp.task('clean', function(done) {
|
||||
return del('out', done);
|
||||
gulp.task('clean', function (done) {
|
||||
return del('out', done);
|
||||
});
|
||||
|
||||
gulp.task('lint', () => {
|
||||
return gulp.src([
|
||||
config.paths.project.root + '/src/**/*.ts',
|
||||
config.paths.project.root + '/test/**/*.ts'
|
||||
])
|
||||
.pipe((tslint({
|
||||
formatter: "verbose"
|
||||
})))
|
||||
.pipe(tslint.report());
|
||||
return gulp.src([
|
||||
config.paths.project.root + '/src/**/*.ts',
|
||||
config.paths.project.root + '/test/**/*.ts'
|
||||
])
|
||||
.pipe((tslint({
|
||||
formatter: "verbose"
|
||||
})))
|
||||
.pipe(tslint.report());
|
||||
});
|
||||
|
||||
gulp.task('compile:src', function(done) {
|
||||
gulp.src([
|
||||
config.paths.project.root + '/src/**/*.sql',
|
||||
config.paths.project.root + '/src/**/*.svg',
|
||||
config.paths.project.root + '/src/**/*.html'
|
||||
]).pipe(gulp.dest('out/src/'));
|
||||
gulp.task('compile:src', function (done) {
|
||||
gulp.src([
|
||||
config.paths.project.root + '/src/**/*.sql',
|
||||
config.paths.project.root + '/src/**/*.svg',
|
||||
config.paths.project.root + '/src/**/*.html'
|
||||
]).pipe(gulp.dest('out/src/'));
|
||||
|
||||
let srcFiles = [
|
||||
config.paths.project.root + '/src/**/*.ts',
|
||||
config.paths.project.root + '/src/**/*.js',
|
||||
config.paths.project.root + '/typings/**/*.ts'
|
||||
];
|
||||
let srcFiles = [
|
||||
config.paths.project.root + '/src/**/*.ts',
|
||||
config.paths.project.root + '/src/**/*.js',
|
||||
config.paths.project.root + '/typings/**/*.ts'
|
||||
];
|
||||
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(srcmap.init())
|
||||
.pipe(tsProject())
|
||||
.on('error', function() {
|
||||
if(process.env.BUILDMACHINE) {
|
||||
done('Failed to compile extension source, see above.');
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
// TODO: Reinstate localization code
|
||||
// .pipe(nls.rewriteLocalizeCalls())
|
||||
// .pipe(nls.createAdditionalLanguageFiles(nls.coreLanguages, config.paths.project.root + '/localization/i18n', undefined, false))
|
||||
.pipe(srcmap.write('.', { sourceRoot: function(file) { return file.cwd + '/src'; }}))
|
||||
.pipe(gulp.dest('out/src/'));
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(srcmap.init())
|
||||
.pipe(tsProject())
|
||||
.on('error', function () {
|
||||
if (process.env.BUILDMACHINE) {
|
||||
done('Failed to compile extension source, see above.');
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
// TODO: Reinstate localization code
|
||||
// .pipe(nls.rewriteLocalizeCalls())
|
||||
// .pipe(nls.createAdditionalLanguageFiles(nls.coreLanguages, config.paths.project.root + '/localization/i18n', undefined, false))
|
||||
.pipe(srcmap.write('.', { sourceRoot: function (file) { return file.cwd + '/src'; } }))
|
||||
.pipe(gulp.dest('out/src/'));
|
||||
});
|
||||
|
||||
gulp.task('compile:test', function(done) {
|
||||
let srcFiles = [
|
||||
config.paths.project.root + '/test/**/*.ts',
|
||||
config.paths.project.root + '/typings/**/*.ts'
|
||||
];
|
||||
gulp.task('compile:test', function (done) {
|
||||
let srcFiles = [
|
||||
config.paths.project.root + '/test/**/*.ts',
|
||||
config.paths.project.root + '/typings/**/*.ts'
|
||||
];
|
||||
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(srcmap.init())
|
||||
.pipe(tsProject())
|
||||
.on('error', function() {
|
||||
if(process.env.BUILDMACHINE) {
|
||||
done('Failed to compile test source, see above.');
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
.pipe(srcmap.write('.', {sourceRoot: function(file) { return file.cwd + '/test'; }}))
|
||||
.pipe(gulp.dest('out/test/'));
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(srcmap.init())
|
||||
.pipe(tsProject())
|
||||
.on('error', function () {
|
||||
if (process.env.BUILDMACHINE) {
|
||||
done('Failed to compile test source, see above.');
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
.pipe(srcmap.write('.', { sourceRoot: function (file) { return file.cwd + '/test'; } }))
|
||||
.pipe(gulp.dest('out/test/'));
|
||||
});
|
||||
|
||||
// COMPOSED GULP TASKS /////////////////////////////////////////////////////
|
||||
@@ -86,33 +86,38 @@ gulp.task("compile", gulp.series("compile:src", "compile:test"));
|
||||
|
||||
gulp.task("build", gulp.series("clean", "lint", "compile"));
|
||||
|
||||
gulp.task("watch", function() {
|
||||
gulp.watch([config.paths.project.root + '/src/**/*',
|
||||
config.paths.project.root + '/test/**/*.ts'],
|
||||
gulp.series('build'))
|
||||
gulp.task("watch", function () {
|
||||
gulp.watch([config.paths.project.root + '/src/**/*',
|
||||
config.paths.project.root + '/test/**/*.ts'],
|
||||
gulp.series('build'));
|
||||
});
|
||||
|
||||
gulp.task('test', (done) => {
|
||||
let workspace = process.env['WORKSPACE'];
|
||||
if (!workspace) {
|
||||
workspace = process.cwd();
|
||||
}
|
||||
process.env.JUNIT_REPORT_PATH = workspace + '/test-reports/ext_xunit.xml';
|
||||
let workspace = process.env['WORKSPACE'];
|
||||
if (!workspace) {
|
||||
workspace = process.cwd();
|
||||
}
|
||||
process.env.JUNIT_REPORT_PATH = workspace + '/test-reports/ext_xunit.xml';
|
||||
|
||||
let azuredatastudioPath = 'azuredatastudio';
|
||||
if (process.env['SQLOPS_DEV']) {
|
||||
let suffix = os.platform === 'win32' ? 'bat' : 'sh';
|
||||
azuredatastudioPath = `${process.env['SQLOPS_DEV']}/scripts/sql-cli.${suffix}`;
|
||||
}
|
||||
console.log(`Using SQLOPS Path of ${azuredatastudioPath}`);
|
||||
let azuredatastudioPath = 'azuredatastudio';
|
||||
if (process.env['SQLOPS_DEV']) {
|
||||
let suffix = os.platform === 'win32' ? 'bat' : 'sh';
|
||||
azuredatastudioPath = `${process.env['SQLOPS_DEV']}/scripts/sql-cli.${suffix}`;
|
||||
}
|
||||
console.log(`Using SQLOPS Path of ${azuredatastudioPath}`);
|
||||
|
||||
cproc.exec(`${azuredatastudioPath} --extensionDevelopmentPath="${workspace}" --extensionTestsPath="${workspace}/out/test" --verbose`, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error(`exec error: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`stdout: ${stdout}`);
|
||||
console.log(`stderr: ${stderr}`);
|
||||
done();
|
||||
});
|
||||
cproc.exec(`${azuredatastudioPath} --extensionDevelopmentPath="${workspace}" --extensionTestsPath="${workspace}/out/test" --verbose`, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error(`exec error: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`stdout: ${stdout}`);
|
||||
console.log(`stderr: ${stderr}`);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('copytypings', function () {
|
||||
return gulp.src(config.paths.project.root + '/../../src/sql/sqlops.proposed.d.ts')
|
||||
.pipe(gulp.dest('typings/'));
|
||||
});
|
||||
|
||||
2
samples/sp_whoIsActive/.gitignore
vendored
@@ -6,4 +6,4 @@ node_modules
|
||||
.DS_Store
|
||||
.idea
|
||||
test-reports/**
|
||||
typings/sqlops.proposed.d.ts
|
||||
typings/azdata.d.ts
|
||||
|
||||
46
samples/sp_whoIsActive/.vscode/launch.json
vendored
@@ -9,7 +9,7 @@
|
||||
// - open Azure Data Studio
|
||||
// - run the command "Install 'azuredatastudio' command in PATH"
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
@@ -21,37 +21,37 @@
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"name": "Attach to Ops Studio",
|
||||
"protocol": "inspector",
|
||||
"port": 5870,
|
||||
"restart": true,
|
||||
{
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"name": "Attach to Azure Data Studio",
|
||||
"protocol": "inspector",
|
||||
"port": 5870,
|
||||
"restart": true,
|
||||
"sourceMaps": true,
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/out/**/*.js"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/out/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "",
|
||||
"timeout": 25000
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "Debug in enlistment",
|
||||
"type": "sqlopsExtensionHost",
|
||||
"type": "azuredatastudioExtensionHost",
|
||||
"request": "launch",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceFolder}/../../scripts/sql.bat"
|
||||
},
|
||||
"osx": {
|
||||
"runtimeExecutable": "${workspaceFolder}/../../scripts/sql.sh"
|
||||
},
|
||||
"linux": {
|
||||
"runtimeExecutable": "${workspaceFolder}/../../scripts/sql.sh"
|
||||
},
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceFolder}/../../scripts/sql.bat"
|
||||
},
|
||||
"osx": {
|
||||
"runtimeExecutable": "${workspaceFolder}/../../scripts/sql.sh"
|
||||
},
|
||||
"linux": {
|
||||
"runtimeExecutable": "${workspaceFolder}/../../scripts/sql.sh"
|
||||
},
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
||||
],
|
||||
"timeout": 20000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
773
samples/sp_whoIsActive/package-lock.json
generated
@@ -2,12 +2,12 @@
|
||||
"name": "whoisactive",
|
||||
"displayName": "whoisactive",
|
||||
"description": "sp_whoisactive for Azure Data Studio",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"engines": {
|
||||
"vscode": "^1.26.0",
|
||||
"azdata": "*"
|
||||
"azdata": "^1.11.0"
|
||||
},
|
||||
"icon": "images/sqlserver.png",
|
||||
"license": "SEE LICENSE IN LICENSE.txt",
|
||||
@@ -241,17 +241,17 @@
|
||||
"compile": "gulp compile",
|
||||
"watch": "gulp watch",
|
||||
"typings": "gulp copytypings",
|
||||
"postinstall": "node ./node_modules/vscode/bin/install && node ./node_modules/sqlops/bin/install && gulp copytypings"
|
||||
"postinstall": "node ./node_modules/vscode/bin/install && node ./node_modules/azdata/bin/install && gulp copytypings"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": "^5.0.0",
|
||||
"handlebars": "^4.0.11",
|
||||
"openurl": "^1.1.1",
|
||||
"sqlops": "github:anthonydresser/sqlops-extension-sqlops"
|
||||
"openurl": "^1.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^2.2.42",
|
||||
"@types/node": "^7.0.43",
|
||||
"azdata": "github:microsoft/azdata-extension-azdata",
|
||||
"child-process-promise": "^2.2.1",
|
||||
"del": "^3.0.0",
|
||||
"gulp": "^4.0.0",
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
@@ -9,18 +8,18 @@
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export default abstract class ControllerBase implements vscode.Disposable {
|
||||
protected _context: vscode.ExtensionContext;
|
||||
protected _context: vscode.ExtensionContext;
|
||||
|
||||
public constructor(context: vscode.ExtensionContext) {
|
||||
this._context = context;
|
||||
}
|
||||
public constructor(context: vscode.ExtensionContext) {
|
||||
this._context = context;
|
||||
}
|
||||
|
||||
abstract activate(): Promise<boolean>;
|
||||
abstract activate(): Promise<boolean>;
|
||||
|
||||
abstract deactivate(): void;
|
||||
abstract deactivate(): void;
|
||||
|
||||
public dispose(): void {
|
||||
this.deactivate();
|
||||
}
|
||||
public dispose(): void {
|
||||
this.deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as azdata from 'azdata';
|
||||
import * as Utils from '../utils';
|
||||
import ControllerBase from './controllerBase';
|
||||
import * as fs from 'fs';
|
||||
@@ -19,35 +19,35 @@ import * as openurl from 'openurl';
|
||||
*/
|
||||
export default class MainController extends ControllerBase {
|
||||
|
||||
public apiWrapper;
|
||||
// PUBLIC METHODS //////////////////////////////////////////////////////
|
||||
/**
|
||||
* Deactivates the extension
|
||||
*/
|
||||
public deactivate(): void {
|
||||
Utils.logDebug('Main controller deactivated');
|
||||
}
|
||||
public apiWrapper;
|
||||
// PUBLIC METHODS //////////////////////////////////////////////////////
|
||||
/**
|
||||
* Deactivates the extension
|
||||
*/
|
||||
public deactivate(): void {
|
||||
Utils.logDebug('Main controller deactivated');
|
||||
}
|
||||
|
||||
public activate(): Promise<boolean> {
|
||||
sqlops.tasks.registerTask('sp_whoisactive.install', e => this.openurl('http://whoisactive.com/downloads/'));
|
||||
sqlops.tasks.registerTask('sp_whoisactive.documentation', e => this.openurl('http://whoisactive.com/docs/'));
|
||||
sqlops.tasks.registerTask('sp_whoisactive.findBlockLeaders', e => this.onExecute(e, 'findBlockLeaders.sql'));
|
||||
sqlops.tasks.registerTask('sp_whoisactive.getPlans', e => this.onExecute(e, 'getPlans.sql'));
|
||||
public activate(): Promise<boolean> {
|
||||
azdata.tasks.registerTask('sp_whoisactive.install', e => this.openurl('http://whoisactive.com/downloads/'));
|
||||
azdata.tasks.registerTask('sp_whoisactive.documentation', e => this.openurl('http://whoisactive.com/docs/'));
|
||||
azdata.tasks.registerTask('sp_whoisactive.findBlockLeaders', e => this.onExecute(e, 'findBlockLeaders.sql'));
|
||||
azdata.tasks.registerTask('sp_whoisactive.getPlans', e => this.onExecute(e, 'getPlans.sql'));
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
private openurl(link: string): void {
|
||||
openurl.open(link);
|
||||
}
|
||||
private openurl(link: string): void {
|
||||
openurl.open(link);
|
||||
}
|
||||
|
||||
private onExecute(connection: sqlops.IConnectionProfile, fileName: string): void {
|
||||
let sqlContent = fs.readFileSync(path.join(__dirname, '..', 'sql', fileName)).toString();
|
||||
vscode.workspace.openTextDocument({language: 'sql', content: sqlContent}).then(doc => {
|
||||
vscode.window.showTextDocument(doc, vscode.ViewColumn.Active, false).then(() => {
|
||||
let filePath = doc.uri.toString();
|
||||
sqlops.queryeditor.connect(filePath, connection.id).then(() => sqlops.queryeditor.runQuery(filePath));
|
||||
});
|
||||
});
|
||||
}
|
||||
private onExecute(connection: azdata.IConnectionProfile, fileName: string): void {
|
||||
let sqlContent = fs.readFileSync(path.join(__dirname, '..', 'sql', fileName)).toString();
|
||||
vscode.workspace.openTextDocument({language: 'sql', content: sqlContent}).then(doc => {
|
||||
vscode.window.showTextDocument(doc, vscode.ViewColumn.Active, false).then(() => {
|
||||
let filePath = doc.uri.toString();
|
||||
azdata.queryeditor.connect(filePath, connection.id).then(() => azdata.queryeditor.runQuery(filePath));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ let tslint = require('gulp-tslint');
|
||||
let ts = require('gulp-typescript');
|
||||
let cproc = require('child_process');
|
||||
let os = require('os');
|
||||
let path = require('path');
|
||||
|
||||
let config = require('./config');
|
||||
let tsProject = ts.createProject('tsconfig.json');
|
||||
@@ -19,66 +20,66 @@ let tsProject = ts.createProject('tsconfig.json');
|
||||
|
||||
// GULP TASKS //////////////////////////////////////////////////////////////
|
||||
gulp.task('clean', function(done) {
|
||||
return del('out', done);
|
||||
return del('out', done);
|
||||
});
|
||||
|
||||
gulp.task('lint', () => {
|
||||
return gulp.src([
|
||||
config.paths.project.root + '/src/**/*.ts',
|
||||
config.paths.project.root + '/test/**/*.ts'
|
||||
])
|
||||
.pipe((tslint({
|
||||
formatter: "verbose"
|
||||
})))
|
||||
.pipe(tslint.report());
|
||||
return gulp.src([
|
||||
config.paths.project.root + '/src/**/*.ts',
|
||||
config.paths.project.root + '/test/**/*.ts'
|
||||
])
|
||||
.pipe((tslint({
|
||||
formatter: "verbose"
|
||||
})))
|
||||
.pipe(tslint.report());
|
||||
});
|
||||
|
||||
gulp.task('compile:src', function(done) {
|
||||
gulp.src([
|
||||
config.paths.project.root + '/src/**/*.sql',
|
||||
config.paths.project.root + '/src/**/*.svg',
|
||||
config.paths.project.root + '/src/**/*.html'
|
||||
]).pipe(gulp.dest('out/src/'));
|
||||
gulp.src([
|
||||
config.paths.project.root + '/src/**/*.sql',
|
||||
config.paths.project.root + '/src/**/*.svg',
|
||||
config.paths.project.root + '/src/**/*.html'
|
||||
]).pipe(gulp.dest('out/src/'));
|
||||
|
||||
let srcFiles = [
|
||||
config.paths.project.root + '/src/**/*.ts',
|
||||
config.paths.project.root + '/src/**/*.js',
|
||||
config.paths.project.root + '/typings/**/*.ts'
|
||||
];
|
||||
let srcFiles = [
|
||||
config.paths.project.root + '/src/**/*.ts',
|
||||
config.paths.project.root + '/src/**/*.js',
|
||||
config.paths.project.root + '/typings/**/*.ts'
|
||||
];
|
||||
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(srcmap.init())
|
||||
.pipe(tsProject())
|
||||
.on('error', function() {
|
||||
if(process.env.BUILDMACHINE) {
|
||||
done('Failed to compile extension source, see above.');
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
// TODO: Reinstate localization code
|
||||
// .pipe(nls.rewriteLocalizeCalls())
|
||||
// .pipe(nls.createAdditionalLanguageFiles(nls.coreLanguages, config.paths.project.root + '/localization/i18n', undefined, false))
|
||||
.pipe(srcmap.write('.', { sourceRoot: function(file) { return file.cwd + '/src'; }}))
|
||||
.pipe(gulp.dest('out/src/'));
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(srcmap.init())
|
||||
.pipe(tsProject())
|
||||
.on('error', function() {
|
||||
if(process.env.BUILDMACHINE) {
|
||||
done('Failed to compile extension source, see above.');
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
// TODO: Reinstate localization code
|
||||
// .pipe(nls.rewriteLocalizeCalls())
|
||||
// .pipe(nls.createAdditionalLanguageFiles(nls.coreLanguages, config.paths.project.root + '/localization/i18n', undefined, false))
|
||||
.pipe(srcmap.write('.', { sourceRoot: function(file) { return file.cwd + '/src'; }}))
|
||||
.pipe(gulp.dest('out/src/'));
|
||||
});
|
||||
|
||||
gulp.task('compile:test', function(done) {
|
||||
let srcFiles = [
|
||||
config.paths.project.root + '/test/**/*.ts',
|
||||
config.paths.project.root + '/typings/**/*.ts'
|
||||
];
|
||||
let srcFiles = [
|
||||
config.paths.project.root + '/test/**/*.ts',
|
||||
config.paths.project.root + '/typings/**/*.ts'
|
||||
];
|
||||
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(srcmap.init())
|
||||
.pipe(tsProject())
|
||||
.on('error', function() {
|
||||
if(process.env.BUILDMACHINE) {
|
||||
done('Failed to compile test source, see above.');
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
.pipe(srcmap.write('.', {sourceRoot: function(file) { return file.cwd + '/test'; }}))
|
||||
.pipe(gulp.dest('out/test/'));
|
||||
return gulp.src(srcFiles)
|
||||
.pipe(srcmap.init())
|
||||
.pipe(tsProject())
|
||||
.on('error', function() {
|
||||
if(process.env.BUILDMACHINE) {
|
||||
done('Failed to compile test source, see above.');
|
||||
process.exit(1);
|
||||
}
|
||||
})
|
||||
.pipe(srcmap.write('.', {sourceRoot: function(file) { return file.cwd + '/test'; }}))
|
||||
.pipe(gulp.dest('out/test/'));
|
||||
});
|
||||
|
||||
// COMPOSED GULP TASKS /////////////////////////////////////////////////////
|
||||
@@ -87,37 +88,37 @@ gulp.task("compile", gulp.series("compile:src", "compile:test"));
|
||||
gulp.task("build", gulp.series("clean", "lint", "compile"));
|
||||
|
||||
gulp.task("watch", function() {
|
||||
gulp.watch([config.paths.project.root + '/src/**/*',
|
||||
config.paths.project.root + '/test/**/*.ts'],
|
||||
gulp.series('build'))
|
||||
gulp.watch([config.paths.project.root + '/src/**/*',
|
||||
config.paths.project.root + '/test/**/*.ts'],
|
||||
gulp.series('build'));
|
||||
});
|
||||
|
||||
gulp.task('test', (done) => {
|
||||
let workspace = process.env['WORKSPACE'];
|
||||
if (!workspace) {
|
||||
workspace = process.cwd();
|
||||
}
|
||||
process.env.JUNIT_REPORT_PATH = workspace + '/test-reports/ext_xunit.xml';
|
||||
let workspace = process.env['WORKSPACE'];
|
||||
if (!workspace) {
|
||||
workspace = process.cwd();
|
||||
}
|
||||
process.env.JUNIT_REPORT_PATH = workspace + '/test-reports/ext_xunit.xml';
|
||||
|
||||
let azuredatastudioPath = 'azuredatastudio';
|
||||
if (process.env['SQLOPS_DEV']) {
|
||||
let suffix = os.platform === 'win32' ? 'bat' : 'sh';
|
||||
azuredatastudioPath = `${process.env['SQLOPS_DEV']}/scripts/sql-cli.${suffix}`;
|
||||
}
|
||||
console.log(`Using SQLOPS Path of ${azuredatastudioPath}`);
|
||||
let azuredatastudioPath = 'azuredatastudio';
|
||||
if (process.env['VSCODE_DEV']) {
|
||||
let suffix = os.platform === 'win32' ? 'bat' : 'sh';
|
||||
azuredatastudioPath = `${process.env['VSCODE_DEV']}/scripts/sql-cli.${suffix}`;
|
||||
}
|
||||
console.log(`Using ADS Path of ${azuredatastudioPath}`);
|
||||
|
||||
cproc.exec(`${azuredatastudioPath} --extensionDevelopmentPath="${workspace}" --extensionTestsPath="${workspace}/out/test" --verbose`, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error(`exec error: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`stdout: ${stdout}`);
|
||||
console.log(`stderr: ${stderr}`);
|
||||
done();
|
||||
});
|
||||
cproc.exec(`${azuredatastudioPath} --extensionDevelopmentPath="${workspace}" --extensionTestsPath="${workspace}/out/test" --verbose`, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error(`exec error: ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`stdout: ${stdout}`);
|
||||
console.log(`stderr: ${stderr}`);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('copytypings', function() {
|
||||
return gulp.src(config.paths.project.root + '/../../src/sql/sqlops.proposed.d.ts')
|
||||
.pipe(gulp.dest('typings/'));
|
||||
return gulp.src(config.paths.project.root + '/../../src/sql/azdata.d.ts')
|
||||
.pipe(gulp.dest('typings/'));
|
||||
});
|
||||
|
||||
@@ -1,123 +1,123 @@
|
||||
{
|
||||
"rules": {
|
||||
"align": [
|
||||
true,
|
||||
"parameters",
|
||||
"statements"
|
||||
],
|
||||
"ban": false,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"indent": [
|
||||
true,
|
||||
"spaces"
|
||||
],
|
||||
"interface-name": true,
|
||||
"jsdoc-format": true,
|
||||
"label-position": true,
|
||||
"label-undefined": true,
|
||||
"max-line-length": [
|
||||
true,
|
||||
160
|
||||
],
|
||||
"member-access": false,
|
||||
"member-ordering": false,
|
||||
"no-any": false,
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-conditional-assignment": true,
|
||||
"no-consecutive-blank-lines": false,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-construct": true,
|
||||
"no-constructor-vars": false,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-key": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-empty": true,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": false,
|
||||
"no-internal-module": true,
|
||||
"no-null-keyword": true,
|
||||
"no-require-imports": false,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-switch-case-fall-through": false,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unreachable": true,
|
||||
"no-unused-expression": false,
|
||||
"no-unused-variable": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"no-var-requires": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-finally",
|
||||
"check-whitespace"
|
||||
],
|
||||
"quotemark": [
|
||||
true,
|
||||
"single",
|
||||
"avoid-escape"
|
||||
],
|
||||
"radix": true,
|
||||
"semicolon": true,
|
||||
"switch-default": true,
|
||||
"trailing-comma": [
|
||||
true,
|
||||
{
|
||||
"multiline": "never",
|
||||
"singleline": "never"
|
||||
}
|
||||
],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef": [
|
||||
true,
|
||||
"call-signature",
|
||||
"property-declaration"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"use-strict": false,
|
||||
"variable-name": [
|
||||
true,
|
||||
"allow-leading-underscore",
|
||||
"ban-keywords"
|
||||
],
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
]
|
||||
}
|
||||
}
|
||||
"rules": {
|
||||
"align": [
|
||||
true,
|
||||
"parameters",
|
||||
"statements"
|
||||
],
|
||||
"ban": false,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"indent": [
|
||||
true,
|
||||
"tabs"
|
||||
],
|
||||
"interface-name": true,
|
||||
"jsdoc-format": true,
|
||||
"label-position": true,
|
||||
"label-undefined": true,
|
||||
"max-line-length": [
|
||||
true,
|
||||
160
|
||||
],
|
||||
"member-access": false,
|
||||
"member-ordering": false,
|
||||
"no-any": false,
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-conditional-assignment": true,
|
||||
"no-consecutive-blank-lines": false,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-construct": true,
|
||||
"no-constructor-vars": false,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-key": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-empty": true,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": false,
|
||||
"no-internal-module": true,
|
||||
"no-null-keyword": true,
|
||||
"no-require-imports": false,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-switch-case-fall-through": false,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unreachable": true,
|
||||
"no-unused-expression": false,
|
||||
"no-unused-variable": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"no-var-requires": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-finally",
|
||||
"check-whitespace"
|
||||
],
|
||||
"quotemark": [
|
||||
true,
|
||||
"single",
|
||||
"avoid-escape"
|
||||
],
|
||||
"radix": true,
|
||||
"semicolon": true,
|
||||
"switch-default": true,
|
||||
"trailing-comma": [
|
||||
true,
|
||||
{
|
||||
"multiline": "never",
|
||||
"singleline": "never"
|
||||
}
|
||||
],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef": [
|
||||
true,
|
||||
"call-signature",
|
||||
"property-declaration"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"use-strict": false,
|
||||
"variable-name": [
|
||||
true,
|
||||
"allow-leading-underscore",
|
||||
"ban-keywords"
|
||||
],
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
21
src/sql/azdata.d.ts
vendored
@@ -3051,10 +3051,9 @@ declare module 'azdata' {
|
||||
focused?: boolean;
|
||||
}
|
||||
|
||||
export interface TextComponentProperties {
|
||||
export interface TextComponentProperties extends ComponentProperties, TitledComponentProperties {
|
||||
value?: string;
|
||||
links?: LinkArea[];
|
||||
CSSStyles?: { [key: string]: string };
|
||||
}
|
||||
|
||||
export interface LinkArea {
|
||||
@@ -3062,7 +3061,7 @@ declare module 'azdata' {
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface HyperlinkComponentProperties extends ComponentProperties {
|
||||
export interface HyperlinkComponentProperties extends ComponentProperties, TitledComponentProperties {
|
||||
label: string;
|
||||
url: string;
|
||||
}
|
||||
@@ -3165,6 +3164,13 @@ declare module 'azdata' {
|
||||
clickable?: boolean;
|
||||
}
|
||||
|
||||
export interface TitledComponentProperties {
|
||||
/**
|
||||
* The title for the component. This title will show when hovered over
|
||||
*/
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface CardComponent extends Component, CardProperties {
|
||||
onDidActionClick: vscode.Event<ActionDescriptor>;
|
||||
onCardSelectedChanged: vscode.Event<any>;
|
||||
@@ -3174,8 +3180,7 @@ declare module 'azdata' {
|
||||
|
||||
}
|
||||
|
||||
export interface TextComponent extends Component, ComponentProperties {
|
||||
value: string;
|
||||
export interface TextComponent extends Component, TextComponentProperties {
|
||||
/**
|
||||
* An event called when the text is clicked
|
||||
*/
|
||||
@@ -3183,8 +3188,6 @@ declare module 'azdata' {
|
||||
}
|
||||
|
||||
export interface HyperlinkComponent extends Component, HyperlinkComponentProperties {
|
||||
label: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface InputBoxComponent extends Component, InputBoxProperties {
|
||||
@@ -3785,7 +3788,7 @@ declare module 'azdata' {
|
||||
* Namespace for interacting with query editor
|
||||
*/
|
||||
export namespace queryeditor {
|
||||
export type QueryEvent =
|
||||
export type QueryEventType =
|
||||
| 'queryStart'
|
||||
| 'queryUpdate'
|
||||
| 'queryStop'
|
||||
@@ -3800,7 +3803,7 @@ declare module 'azdata' {
|
||||
* visualize: ResultSetSummary
|
||||
*/
|
||||
export interface QueryEventListener {
|
||||
onQueryEvent(type: QueryEvent, document: queryeditor.QueryDocument, args: ResultSetSummary | string | undefined): void;
|
||||
onQueryEvent(type: QueryEventType, document: queryeditor.QueryDocument, args: ResultSetSummary | string | undefined): void;
|
||||
}
|
||||
|
||||
// new extensibility interfaces
|
||||
|
||||
@@ -28,6 +28,7 @@ export interface ICellRangeSelectorOptions {
|
||||
export interface ICellRangeSelector<T> extends Slick.Plugin<T> {
|
||||
onCellRangeSelected: Slick.Event<Slick.Range>;
|
||||
onBeforeCellRangeSelected: Slick.Event<Slick.Cell>;
|
||||
onAppendCellRangeSelected: Slick.Event<Slick.Range>;
|
||||
}
|
||||
|
||||
export interface ICellRangeDecorator {
|
||||
@@ -45,6 +46,7 @@ export class CellRangeSelector<T> implements ICellRangeSelector<T> {
|
||||
|
||||
public onBeforeCellRangeSelected = new Slick.Event<Slick.Cell>();
|
||||
public onCellRangeSelected = new Slick.Event<Slick.Range>();
|
||||
public onAppendCellRangeSelected = new Slick.Event<Slick.Range>();
|
||||
|
||||
constructor(private options: ICellRangeSelectorOptions) {
|
||||
require.__$__nodeRequire('slickgrid/plugins/slick.cellrangedecorator');
|
||||
@@ -138,11 +140,18 @@ export class CellRangeSelector<T> implements ICellRangeSelector<T> {
|
||||
if (!dd || !dd.range || !dd.range.start || !dd.range.end) {
|
||||
return;
|
||||
}
|
||||
this.onCellRangeSelected.notify(new Slick.Range(
|
||||
|
||||
let newRange = new Slick.Range(
|
||||
dd.range.start.row,
|
||||
dd.range.start.cell,
|
||||
dd.range.end.row,
|
||||
dd.range.end.cell
|
||||
));
|
||||
);
|
||||
|
||||
if (e.ctrlKey) {
|
||||
this.onAppendCellRangeSelected.notify(newRange);
|
||||
} else {
|
||||
this.onCellRangeSelected.notify(newRange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,11 +36,14 @@ export class CellSelectionModel<T> implements Slick.SelectionModel<T, Array<Slic
|
||||
|
||||
public init(grid: Slick.Grid<T>) {
|
||||
this.grid = grid;
|
||||
this._handler.subscribe(this.grid.onActiveCellChanged, (e: Event, args: Slick.OnActiveCellChangedEventArgs<T>) => this.handleActiveCellChange(e, args));
|
||||
this._handler.subscribe(this.grid.onClick, (e: MouseEvent, args: Slick.OnActiveCellChangedEventArgs<T>) => this.handleActiveCellChange(e, args));
|
||||
this._handler.subscribe(this.grid.onKeyDown, (e: KeyboardEvent) => this.handleKeyDown(e));
|
||||
this._handler.subscribe(this.grid.onClick, (e: MouseEvent, args: Slick.OnClickEventArgs<T>) => this.handleIndividualCellSelection(e, args));
|
||||
this._handler.subscribe(this.grid.onHeaderClick, (e: MouseEvent, args: Slick.OnHeaderClickEventArgs<T>) => this.handleHeaderClick(e, args));
|
||||
this.grid.registerPlugin(this.selector);
|
||||
this._handler.subscribe(this.selector.onCellRangeSelected, (e: Event, range: Slick.Range) => this.handleCellRangeSelected(e, range));
|
||||
this._handler.subscribe(this.selector.onCellRangeSelected, (e: Event, range: Slick.Range) => this.handleCellRangeSelected(e, range, false));
|
||||
this._handler.subscribe(this.selector.onAppendCellRangeSelected, (e: Event, range: Slick.Range) => this.handleCellRangeSelected(e, range, true));
|
||||
|
||||
this._handler.subscribe(this.selector.onBeforeCellRangeSelected, (e: Event, cell: Slick.Cell) => this.handleBeforeCellRangeSelected(e, cell));
|
||||
}
|
||||
|
||||
@@ -87,13 +90,18 @@ export class CellSelectionModel<T> implements Slick.SelectionModel<T, Array<Slic
|
||||
return true;
|
||||
}
|
||||
|
||||
private handleCellRangeSelected(e: Event, range: Slick.Range) {
|
||||
private handleCellRangeSelected(e: Event, range: Slick.Range, append: boolean) {
|
||||
this.grid.setActiveCell(range.fromRow, range.fromCell, false, false, true);
|
||||
this.setSelectedRanges([range]);
|
||||
|
||||
if (append) {
|
||||
this.setSelectedRanges(this.insertIntoSelections(this.getSelectedRanges(), range));
|
||||
} else {
|
||||
this.setSelectedRanges([range]);
|
||||
}
|
||||
}
|
||||
|
||||
private handleActiveCellChange(e: Event, args: Slick.OnActiveCellChangedEventArgs<T>) {
|
||||
if (this.options.selectActiveCell && !isUndefinedOrNull(args.row) && !isUndefinedOrNull(args.cell)) {
|
||||
private handleActiveCellChange(e: MouseEvent, args: Slick.OnActiveCellChangedEventArgs<T>) {
|
||||
if (this.options.selectActiveCell && !isUndefinedOrNull(args.row) && !isUndefinedOrNull(args.cell) && !e.ctrlKey) {
|
||||
this.setSelectedRanges([new Slick.Range(args.row, args.cell)]);
|
||||
} else if (!this.options.selectActiveCell) {
|
||||
// clear the previous selection once the cell changes
|
||||
@@ -118,6 +126,119 @@ export class CellSelectionModel<T> implements Slick.SelectionModel<T, Array<Slic
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DO NOT CALL THIS DIRECTLY - GO THROUGH INSERT INTO SELECTIONS
|
||||
*
|
||||
*/
|
||||
private mergeSelections(ranges: Array<Slick.Range>, range: Slick.Range) {
|
||||
// New ranges selection
|
||||
let newRanges: Array<Slick.Range> = [];
|
||||
|
||||
// Have we handled this value
|
||||
let handled = false;
|
||||
for (let current of ranges) {
|
||||
// We've already processed everything. Add everything left back to the list.
|
||||
if (handled) {
|
||||
newRanges.push(current);
|
||||
continue;
|
||||
}
|
||||
let newRange: Slick.Range | undefined = undefined;
|
||||
|
||||
// if the ranges are the same.
|
||||
if (current.fromRow === range.fromRow &&
|
||||
current.fromCell === range.fromCell &&
|
||||
current.toRow === range.toRow &&
|
||||
current.toCell === range.toCell) {
|
||||
// If we're actually not going to handle it during this loop
|
||||
// this region will be added with the handled boolean check
|
||||
continue;
|
||||
}
|
||||
|
||||
// Rows are the same - horizontal merging of the selection area
|
||||
if (current.fromRow === range.fromRow && current.toRow === range.toRow) {
|
||||
// Check if the new region is adjacent to the old selection group
|
||||
if (range.toCell + 1 === current.fromCell || range.fromCell - 1 === current.toCell) {
|
||||
handled = true;
|
||||
let fromCell = Math.min(range.fromCell, current.fromCell, range.toCell, current.toCell);
|
||||
let toCell = Math.max(range.fromCell, current.fromCell, range.toCell, current.toCell);
|
||||
newRange = new Slick.Range(range.fromRow, fromCell, range.toRow, toCell);
|
||||
}
|
||||
// Cells are the same - vertical merging of the selection area
|
||||
} else if (current.fromCell === range.fromCell && current.toCell === range.toCell) {
|
||||
// Check if the new region is adjacent to the old selection group
|
||||
if (range.toRow + 1 === current.fromRow || range.fromRow - 1 === current.toRow) {
|
||||
handled = true;
|
||||
let fromRow = Math.min(range.fromRow, current.fromRow, range.fromRow, current.fromRow);
|
||||
let toRow = Math.max(range.toRow, current.toRow, range.toRow, current.toRow);
|
||||
newRange = new Slick.Range(fromRow, range.fromCell, toRow, range.toCell);
|
||||
}
|
||||
}
|
||||
|
||||
if (newRange) {
|
||||
newRanges.push(newRange);
|
||||
} else {
|
||||
newRanges.push(current);
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
newRanges.push(range);
|
||||
}
|
||||
|
||||
return {
|
||||
newRanges,
|
||||
handled
|
||||
};
|
||||
}
|
||||
|
||||
private insertIntoSelections(ranges: Array<Slick.Range>, range: Slick.Range): Array<Slick.Range> {
|
||||
let result = this.mergeSelections(ranges, range);
|
||||
let newRanges = result.newRanges;
|
||||
|
||||
// Keep merging the rows until we stop having changes
|
||||
let i = 0;
|
||||
while (true) {
|
||||
if (i++ > 10000) {
|
||||
console.error('InsertIntoSelection infinite loop: Report this error on github');
|
||||
break;
|
||||
}
|
||||
let shouldContinue = false;
|
||||
for (let current of newRanges) {
|
||||
result = this.mergeSelections(newRanges, current);
|
||||
if (result.handled) {
|
||||
shouldContinue = true;
|
||||
newRanges = result.newRanges;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldContinue) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return newRanges;
|
||||
}
|
||||
|
||||
private handleIndividualCellSelection(e: MouseEvent, args: Slick.OnClickEventArgs<T>) {
|
||||
if (!e.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
let ranges: Array<Slick.Range>;
|
||||
|
||||
ranges = this.getSelectedRanges();
|
||||
ranges = this.insertIntoSelections(ranges, new Slick.Range(args.row, args.cell));
|
||||
|
||||
this.grid.setActiveCell(args.row, args.cell);
|
||||
this.setSelectedRanges(ranges);
|
||||
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
private handleKeyDown(e: KeyboardEvent) {
|
||||
/***
|
||||
* Кey codes
|
||||
|
||||
@@ -589,7 +589,7 @@ export class NewNotebookJobAction extends Action {
|
||||
|
||||
export class EditNotebookJobAction extends Action {
|
||||
public static ID = 'notebookaction.editNotebook';
|
||||
public static LABEL = nls.localize('notebookaction.editJob', "Edit Notebook Job");
|
||||
public static LABEL = nls.localize('notebookaction.editJob', "Edit");
|
||||
|
||||
constructor(
|
||||
@ICommandService private _commandService: ICommandService
|
||||
@@ -624,7 +624,7 @@ export class OpenTemplateNotebookAction extends Action {
|
||||
|
||||
export class DeleteNotebookAction extends Action {
|
||||
public static ID = 'notebookaction.deleteNotebook';
|
||||
public static LABEL = nls.localize('notebookaction.deleteNotebook', "Delete Notebook");
|
||||
public static LABEL = nls.localize('notebookaction.deleteNotebook', "Delete");
|
||||
|
||||
constructor(
|
||||
@INotificationService private _notificationService: INotificationService,
|
||||
@@ -732,3 +732,19 @@ export class RenameNotebookMaterializedAction extends Action {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenLatestRunMaterializedNotebook extends Action {
|
||||
public static ID = 'notebookaction.openLatestRun';
|
||||
public static LABEL = nls.localize('notebookaction.openLatestRun', "Open Latest Run");
|
||||
|
||||
constructor(
|
||||
@ICommandService private _commandService: ICommandService,
|
||||
) {
|
||||
super(OpenLatestRunMaterializedNotebook.ID, OpenLatestRunMaterializedNotebook.LABEL);
|
||||
}
|
||||
|
||||
public run(actionInfo: IJobActionInfo): Promise<boolean> {
|
||||
actionInfo.component.openLastNRun(actionInfo.targetObject.job, 0, 1);
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,22 +43,27 @@ export interface IGridDataProvider {
|
||||
}
|
||||
|
||||
export async function getResultsString(provider: IGridDataProvider, selection: Slick.Range[], includeHeaders?: boolean): Promise<string> {
|
||||
let headers: Map<Number, string> = new Map();
|
||||
let rows: Map<Number, Map<Number, string>> = new Map();
|
||||
let copyTable: string[][] = [];
|
||||
const eol = provider.getEolString();
|
||||
|
||||
// create a mapping of the ranges to get promises
|
||||
let tasks = selection.map((range, i) => {
|
||||
return async () => {
|
||||
let selectionsCopy = selection;
|
||||
let startCol = range.fromCell;
|
||||
let startRow = range.fromRow;
|
||||
|
||||
const result = await provider.getRowData(range.fromRow, range.toRow - range.fromRow + 1);
|
||||
// If there was a previous selection separate it with a line break. Currently
|
||||
// when there are multiple selections they are never on the same line
|
||||
if (provider.shouldIncludeHeaders(includeHeaders)) {
|
||||
let columnHeaders = provider.getColumnHeaders(range);
|
||||
if (columnHeaders !== undefined) {
|
||||
if (copyTable[0] === undefined) {
|
||||
copyTable[0] = [];
|
||||
}
|
||||
copyTable[0].push(...columnHeaders);
|
||||
let columnHeaders = provider.getColumnHeaders(range);
|
||||
if (columnHeaders !== undefined) {
|
||||
let idx = 0;
|
||||
for (let header of columnHeaders) {
|
||||
headers.set(startCol + idx, header);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
// Iterate over the rows to paste into the copy string
|
||||
@@ -70,11 +75,17 @@ export async function getResultsString(provider: IGridDataProvider, selection: S
|
||||
? cellObjects.map(x => removeNewLines(x.displayValue))
|
||||
: cellObjects.map(x => x.displayValue);
|
||||
|
||||
let idx = rowIndex + 1;
|
||||
if (copyTable[idx] === undefined) {
|
||||
copyTable[idx] = [];
|
||||
let idx = 0;
|
||||
for (let cell of cells) {
|
||||
let map = rows.get(rowIndex + startRow);
|
||||
if (!map) {
|
||||
map = new Map();
|
||||
rows.set(rowIndex + startRow, map);
|
||||
}
|
||||
|
||||
map.set(startCol + idx, cell);
|
||||
idx++;
|
||||
}
|
||||
copyTable[idx].push(...cells);
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -88,12 +99,25 @@ export async function getResultsString(provider: IGridDataProvider, selection: S
|
||||
}
|
||||
|
||||
let copyString = '';
|
||||
copyTable.forEach((row) => {
|
||||
if (row === undefined) {
|
||||
return;
|
||||
if (includeHeaders) {
|
||||
copyString = [...headers.values()].join('\t').concat(eol);
|
||||
}
|
||||
|
||||
const rowKeys = [...headers.keys()];
|
||||
|
||||
for (let rowEntry of rows) {
|
||||
let rowMap = rowEntry[1];
|
||||
for (let rowIdx of rowKeys) {
|
||||
|
||||
let value = rowMap.get(rowIdx);
|
||||
if (value) {
|
||||
copyString = copyString.concat(value);
|
||||
}
|
||||
copyString = copyString.concat('\t');
|
||||
}
|
||||
copyString = copyString.concat(row.join('\t').concat(eol));
|
||||
});
|
||||
copyString = copyString.concat(eol);
|
||||
}
|
||||
// Removes EoL from the end of the string
|
||||
copyString = copyString.slice(0, -1 * eol.length);
|
||||
|
||||
return copyString;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import QueryRunner from 'sql/platform/query/common/queryRunner';
|
||||
import QueryRunner, { IQueryMessage } from 'sql/platform/query/common/queryRunner';
|
||||
import { DataService } from 'sql/workbench/parts/grid/common/dataService';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
@@ -31,9 +31,15 @@ export interface IQueryPlanInfo {
|
||||
planXml: string;
|
||||
}
|
||||
|
||||
export interface IQueryInfo {
|
||||
selection: ISelectionData[];
|
||||
messages: IQueryMessage[];
|
||||
}
|
||||
|
||||
export interface IQueryEvent {
|
||||
type: queryeditor.QueryEvent;
|
||||
type: queryeditor.QueryEventType;
|
||||
uri: string;
|
||||
queryInfo: IQueryInfo;
|
||||
params?: any;
|
||||
}
|
||||
|
||||
|
||||
@@ -283,7 +283,12 @@ export class QueryModelService implements IQueryModelService {
|
||||
// fire extensibility API event
|
||||
let event: IQueryEvent = {
|
||||
type: 'queryStop',
|
||||
uri: uri
|
||||
uri: uri,
|
||||
queryInfo:
|
||||
{
|
||||
selection: info.selection,
|
||||
messages: info.queryRunner.messages
|
||||
}
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
|
||||
@@ -296,7 +301,12 @@ export class QueryModelService implements IQueryModelService {
|
||||
// fire extensibility API event
|
||||
let event: IQueryEvent = {
|
||||
type: 'queryStart',
|
||||
uri: uri
|
||||
uri: uri,
|
||||
queryInfo:
|
||||
{
|
||||
selection: info.selection,
|
||||
messages: info.queryRunner.messages
|
||||
}
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
|
||||
@@ -307,7 +317,12 @@ export class QueryModelService implements IQueryModelService {
|
||||
|
||||
let event: IQueryEvent = {
|
||||
type: 'queryUpdate',
|
||||
uri: uri
|
||||
uri: uri,
|
||||
queryInfo:
|
||||
{
|
||||
selection: info.selection,
|
||||
messages: info.queryRunner.messages
|
||||
}
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
|
||||
@@ -319,6 +334,11 @@ export class QueryModelService implements IQueryModelService {
|
||||
let event: IQueryEvent = {
|
||||
type: 'executionPlan',
|
||||
uri: planInfo.fileUri,
|
||||
queryInfo:
|
||||
{
|
||||
selection: info.selection,
|
||||
messages: info.queryRunner.messages
|
||||
},
|
||||
params: planInfo
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
@@ -328,6 +348,11 @@ export class QueryModelService implements IQueryModelService {
|
||||
let event: IQueryEvent = {
|
||||
type: 'visualize',
|
||||
uri: uri,
|
||||
queryInfo:
|
||||
{
|
||||
selection: info.selection,
|
||||
messages: info.queryRunner.messages
|
||||
},
|
||||
params: resultSetInfo
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
@@ -443,7 +468,12 @@ export class QueryModelService implements IQueryModelService {
|
||||
// fire extensibility API event
|
||||
let event: IQueryEvent = {
|
||||
type: 'queryStop',
|
||||
uri: ownerUri
|
||||
uri: ownerUri,
|
||||
queryInfo:
|
||||
{
|
||||
selection: info.selection,
|
||||
messages: info.queryRunner.messages
|
||||
},
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
|
||||
@@ -455,7 +485,12 @@ export class QueryModelService implements IQueryModelService {
|
||||
// fire extensibility API event
|
||||
let event: IQueryEvent = {
|
||||
type: 'queryStart',
|
||||
uri: ownerUri
|
||||
uri: ownerUri,
|
||||
queryInfo:
|
||||
{
|
||||
selection: info.selection,
|
||||
messages: info.queryRunner.messages
|
||||
},
|
||||
};
|
||||
this._onQueryEvent.fire(event);
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ export interface IQueryMessage extends azdata.IResultMessage {
|
||||
export default class QueryRunner extends Disposable {
|
||||
// MEMBER VARIABLES ////////////////////////////////////////////////////
|
||||
private _resultLineOffset: number;
|
||||
private _resultColumnOffset: number;
|
||||
private _totalElapsedMilliseconds: number = 0;
|
||||
private _isExecuting: boolean = false;
|
||||
private _hasCompleted: boolean = false;
|
||||
@@ -179,6 +180,7 @@ export default class QueryRunner extends Disposable {
|
||||
if (types.isObject(input) || types.isUndefinedOrNull(input)) {
|
||||
// Update internal state to show that we're executing the query
|
||||
this._resultLineOffset = input ? input.startLine : 0;
|
||||
this._resultColumnOffset = input ? input.startColumn : 0;
|
||||
this._isExecuting = true;
|
||||
this._totalElapsedMilliseconds = 0;
|
||||
// TODO issue #228 add statusview callbacks here
|
||||
@@ -243,8 +245,10 @@ export default class QueryRunner extends Disposable {
|
||||
|
||||
this._batchSets.map(batch => {
|
||||
if (batch.selection) {
|
||||
batch.selection.startLine = batch.selection.startLine + this._resultLineOffset;
|
||||
batch.selection.endLine = batch.selection.endLine + this._resultLineOffset;
|
||||
batch.selection.startLine += this._resultLineOffset;
|
||||
batch.selection.startColumn += this._resultColumnOffset;
|
||||
batch.selection.endLine += this._resultLineOffset;
|
||||
batch.selection.endColumn += this._resultColumnOffset;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -271,7 +275,9 @@ export default class QueryRunner extends Disposable {
|
||||
// Recalculate the start and end lines, relative to the result line offset
|
||||
if (batch.selection) {
|
||||
batch.selection.startLine += this._resultLineOffset;
|
||||
batch.selection.startColumn += this._resultColumnOffset;
|
||||
batch.selection.endLine += this._resultLineOffset;
|
||||
batch.selection.endColumn += this._resultColumnOffset;
|
||||
}
|
||||
|
||||
// Set the result sets as an empty array so that as result sets complete we can add to the list
|
||||
|
||||
34
src/sql/platform/queryHistory/common/queryHistoryInfo.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
|
||||
export enum QueryStatus {
|
||||
Succeeded = 0,
|
||||
Failed = 1,
|
||||
Nothing = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains information about a query that was ran
|
||||
*/
|
||||
export class QueryHistoryInfo {
|
||||
|
||||
public database: string;
|
||||
|
||||
public status: QueryStatus;
|
||||
|
||||
public readonly id = generateUuid();
|
||||
|
||||
constructor(
|
||||
public queryText: string,
|
||||
public connectionProfile: IConnectionProfile,
|
||||
public startTime: Date,
|
||||
status?: QueryStatus) {
|
||||
this.database = connectionProfile ? connectionProfile.databaseName : '';
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
55
src/sql/platform/queryHistory/common/queryHistoryService.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { QueryHistoryInfo } from 'sql/platform/queryHistory/common/queryHistoryInfo';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export const SERVICE_ID = 'queryHistoryService';
|
||||
|
||||
export const IQueryHistoryService = createDecorator<IQueryHistoryService>(SERVICE_ID);
|
||||
|
||||
/**
|
||||
* Service that collects the results of executed queries
|
||||
*/
|
||||
export interface IQueryHistoryService {
|
||||
_serviceBrand: any;
|
||||
|
||||
/**
|
||||
* Event fired whenever the collection of stored QueryHistoryInfo's is updated
|
||||
*/
|
||||
onInfosUpdated: Event<QueryHistoryInfo[]>;
|
||||
/**
|
||||
* Event fired whenever the Query History capture state has changed
|
||||
*/
|
||||
onQueryHistoryCaptureChanged: Event<boolean>;
|
||||
|
||||
/**
|
||||
* Whether Query History capture is currently enabled
|
||||
*/
|
||||
readonly captureEnabled: boolean;
|
||||
|
||||
/**
|
||||
* Gets the current list of Query History Info objects that have been collected
|
||||
*/
|
||||
getQueryHistoryInfos(): QueryHistoryInfo[];
|
||||
/**
|
||||
* Deletes all QueryHistoryInfo's from the collection that have the same id as the specified one
|
||||
* @param info The QueryHistoryInfo to delete
|
||||
*/
|
||||
deleteQueryHistoryInfo(info: QueryHistoryInfo): void;
|
||||
/**
|
||||
* Clears all Query History - removing all collected items
|
||||
*/
|
||||
clearQueryHistory(): void;
|
||||
/**
|
||||
* Toggles whether Query History capture is enabled
|
||||
*/
|
||||
toggleCaptureEnabled(): Promise<void>;
|
||||
/**
|
||||
* Starts the Query History Service
|
||||
*/
|
||||
start(): void;
|
||||
}
|
||||
127
src/sql/platform/queryHistory/common/queryHistoryServiceImpl.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IQueryHistoryService } from 'sql/platform/queryHistory/common/queryHistoryService.ts';
|
||||
|
||||
import { IQueryModelService, IQueryEvent } from 'sql/platform/query/common/queryModel';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { QueryHistoryInfo, QueryStatus } from 'sql/platform/queryHistory/common/queryHistoryInfo';
|
||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
import { IConfigurationChangedEvent } from 'sql/workbench/parts/profiler/browser/profilerFindWidget';
|
||||
|
||||
/**
|
||||
* Service that collects the results of executed queries
|
||||
*/
|
||||
export class QueryHistoryService extends Disposable implements IQueryHistoryService {
|
||||
_serviceBrand: any;
|
||||
|
||||
// MEMBER VARIABLES ////////////////////////////////////////////////////
|
||||
private _infos: QueryHistoryInfo[] = [];
|
||||
private _onInfosUpdated: Emitter<QueryHistoryInfo[]> = new Emitter<QueryHistoryInfo[]>();
|
||||
private _onQueryHistoryCaptureChanged: Emitter<boolean> = new Emitter<boolean>();
|
||||
private _captureEnabled;
|
||||
// EVENTS //////////////////////////////////////////////////////////////
|
||||
public get onInfosUpdated(): Event<QueryHistoryInfo[]> { return this._onInfosUpdated.event; }
|
||||
public get onQueryHistoryCaptureChanged(): Event<boolean> { return this._onQueryHistoryCaptureChanged.event; }
|
||||
// CONSTRUCTOR /////////////////////////////////////////////////////////
|
||||
constructor(
|
||||
@IQueryModelService _queryModelService: IQueryModelService,
|
||||
@IModelService _modelService: IModelService,
|
||||
@IConnectionManagementService _connectionManagementService: IConnectionManagementService,
|
||||
@IConfigurationService private _configurationService: IConfigurationService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._captureEnabled = !!this._configurationService.getValue<boolean>('queryHistory.captureEnabled');
|
||||
|
||||
this._register(this._configurationService.onDidChangeConfiguration((e: IConfigurationChangeEvent) => {
|
||||
if (e.affectedKeys.includes('queryHistory.captureEnabled')) {
|
||||
this.updateCaptureEnabled();
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(_queryModelService.onQueryEvent((e: IQueryEvent) => {
|
||||
if (this._captureEnabled && e.type === 'queryStop') {
|
||||
const uri: URI = URI.parse(e.uri);
|
||||
// VS Range is 1 based so offset values by 1. The endLine we get back from SqlToolsService is incremented
|
||||
// by 1 from the original input range sent in as well so take that into account and don't modify
|
||||
const text: string = _modelService.getModel(uri).getValueInRange(new Range(
|
||||
e.queryInfo.selection[0].startLine + 1,
|
||||
e.queryInfo.selection[0].startColumn + 1,
|
||||
e.queryInfo.selection[0].endLine,
|
||||
e.queryInfo.selection[0].endColumn + 1));
|
||||
|
||||
const newInfo = new QueryHistoryInfo(text, _connectionManagementService.getConnectionProfile(e.uri), new Date(), QueryStatus.Succeeded);
|
||||
|
||||
// icon as required (for now logic is if any message has error query has error)
|
||||
let error: boolean = false;
|
||||
e.queryInfo.messages.forEach(x => error = error || x.isError);
|
||||
if (error) {
|
||||
newInfo.status = QueryStatus.Failed;
|
||||
}
|
||||
|
||||
// Append new node to beginning of array so the newest ones are at the top
|
||||
this._infos.unshift(newInfo);
|
||||
this._onInfosUpdated.fire(this._infos);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether Query History capture is currently enabled
|
||||
*/
|
||||
public get captureEnabled(): boolean {
|
||||
return this._captureEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the current query history infos
|
||||
*/
|
||||
public getQueryHistoryInfos(): QueryHistoryInfo[] {
|
||||
return this._infos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes infos from the cache with the same ID as the given QueryHistoryInfo
|
||||
* @param info The QueryHistoryInfo to delete
|
||||
*/
|
||||
public deleteQueryHistoryInfo(info: QueryHistoryInfo): void {
|
||||
this._infos = this._infos.filter(i => i.id !== info.id);
|
||||
this._onInfosUpdated.fire(this._infos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all infos from the cache
|
||||
*/
|
||||
public clearQueryHistory(): void {
|
||||
this._infos = [];
|
||||
this._onInfosUpdated.fire(this._infos);
|
||||
}
|
||||
|
||||
public async toggleCaptureEnabled(): Promise<void> {
|
||||
const captureEnabled = !!this._configurationService.getValue<boolean>('queryHistory.captureEnabled');
|
||||
await this._configurationService.updateValue('queryHistory.captureEnabled', !captureEnabled);
|
||||
}
|
||||
|
||||
private updateCaptureEnabled(): void {
|
||||
const currentCaptureEnabled = this._captureEnabled;
|
||||
this._captureEnabled = !!this._configurationService.getValue<boolean>('queryHistory.captureEnabled');
|
||||
if (currentCaptureEnabled !== this._captureEnabled) {
|
||||
this._onQueryHistoryCaptureChanged.fire(this._captureEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to force initialization of the service so that it can start tracking query events
|
||||
*/
|
||||
public start(): void {
|
||||
|
||||
}
|
||||
}
|
||||
20
src/sql/sqlops.proposed.d.ts
vendored
@@ -545,7 +545,7 @@ declare module 'sqlops' {
|
||||
checked?: boolean;
|
||||
}
|
||||
|
||||
export interface TextComponentProperties {
|
||||
export interface TextComponentProperties extends ComponentProperties, TitledComponentProperties {
|
||||
value?: string;
|
||||
links?: LinkArea[];
|
||||
}
|
||||
@@ -555,7 +555,7 @@ declare module 'sqlops' {
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface HyperlinkComponentProperties extends ComponentProperties {
|
||||
export interface HyperlinkComponentProperties extends ComponentProperties, TitledComponentProperties {
|
||||
label: string;
|
||||
url: string;
|
||||
}
|
||||
@@ -651,6 +651,13 @@ declare module 'sqlops' {
|
||||
yOffsetChange?: number;
|
||||
}
|
||||
|
||||
export interface TitledComponentProperties {
|
||||
/**
|
||||
* The title for the component. This title will show when hovered over
|
||||
*/
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface CardComponent extends Component, CardProperties {
|
||||
onDidActionClick: vscode.Event<ActionDescriptor>;
|
||||
onCardSelectedChanged: vscode.Event<any>;
|
||||
@@ -660,13 +667,14 @@ declare module 'sqlops' {
|
||||
|
||||
}
|
||||
|
||||
export interface TextComponent extends Component, ComponentProperties {
|
||||
value: string;
|
||||
export interface TextComponent extends Component, TextComponentProperties {
|
||||
/**
|
||||
* An event called when the text is clicked
|
||||
*/
|
||||
onDidClick: vscode.Event<any>;
|
||||
}
|
||||
|
||||
export interface HyperlinkComponent extends Component, HyperlinkComponentProperties {
|
||||
label: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface InputBoxComponent extends Component, InputBoxProperties {
|
||||
|
||||
@@ -1112,6 +1112,13 @@ class TextComponentWrapper extends ComponentWrapper implements azdata.TextCompon
|
||||
this.setProperty('value', v);
|
||||
}
|
||||
|
||||
public get title(): string {
|
||||
return this.properties['title'];
|
||||
}
|
||||
public set title(title: string) {
|
||||
this.setProperty('title', title);
|
||||
}
|
||||
|
||||
public get onDidClick(): vscode.Event<any> {
|
||||
let emitter = this._emitterMap.get(ComponentEventType.onDidClick);
|
||||
return emitter && emitter.event;
|
||||
|
||||
@@ -326,8 +326,8 @@ export enum DataProviderType {
|
||||
AgentServicesProvider = 'AgentServicesProvider',
|
||||
CapabilitiesProvider = 'CapabilitiesProvider',
|
||||
ObjectExplorerNodeProvider = 'ObjectExplorerNodeProvider',
|
||||
IconProvider = 'IconProvider',
|
||||
SerializationProvider = 'SerializationProvider'
|
||||
SerializationProvider = 'SerializationProvider',
|
||||
IconProvider = 'IconProvider'
|
||||
}
|
||||
|
||||
export enum DeclarativeDataType {
|
||||
@@ -579,10 +579,96 @@ export class ConnectionProfile {
|
||||
options: { [name: string]: any };
|
||||
|
||||
static createFrom(options: any[]): ConnectionProfile {
|
||||
throw new Error('Method not implemented');
|
||||
// create from options
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export enum SchemaUpdateAction {
|
||||
Delete = 0,
|
||||
Change = 1,
|
||||
Add = 2
|
||||
}
|
||||
|
||||
export enum SchemaDifferenceType {
|
||||
Object = 0,
|
||||
Property = 1
|
||||
}
|
||||
|
||||
export enum SchemaCompareEndpointType {
|
||||
Database = 0,
|
||||
Dacpac = 1
|
||||
}
|
||||
|
||||
export enum SchemaObjectType {
|
||||
Aggregates = 0,
|
||||
ApplicationRoles = 1,
|
||||
Assemblies = 2,
|
||||
AssemblyFiles = 3,
|
||||
AsymmetricKeys = 4,
|
||||
BrokerPriorities = 5,
|
||||
Certificates = 6,
|
||||
ColumnEncryptionKeys = 7,
|
||||
ColumnMasterKeys = 8,
|
||||
Contracts = 9,
|
||||
DatabaseOptions = 10,
|
||||
DatabaseRoles = 11,
|
||||
DatabaseTriggers = 12,
|
||||
Defaults = 13,
|
||||
ExtendedProperties = 14,
|
||||
ExternalDataSources = 15,
|
||||
ExternalFileFormats = 16,
|
||||
ExternalTables = 17,
|
||||
Filegroups = 18,
|
||||
FileTables = 19,
|
||||
FullTextCatalogs = 20,
|
||||
FullTextStoplists = 21,
|
||||
MessageTypes = 22,
|
||||
PartitionFunctions = 23,
|
||||
PartitionSchemes = 24,
|
||||
Permissions = 25,
|
||||
Queues = 26,
|
||||
RemoteServiceBindings = 27,
|
||||
RoleMembership = 28,
|
||||
Rules = 29,
|
||||
ScalarValuedFunctions = 30,
|
||||
SearchPropertyLists = 31,
|
||||
SecurityPolicies = 32,
|
||||
Sequences = 33,
|
||||
Services = 34,
|
||||
Signatures = 35,
|
||||
StoredProcedures = 36,
|
||||
SymmetricKeys = 37,
|
||||
Synonyms = 38,
|
||||
Tables = 39,
|
||||
TableValuedFunctions = 40,
|
||||
UserDefinedDataTypes = 41,
|
||||
UserDefinedTableTypes = 42,
|
||||
ClrUserDefinedTypes = 43,
|
||||
Users = 44,
|
||||
Views = 45,
|
||||
XmlSchemaCollections = 46,
|
||||
Audits = 47,
|
||||
Credentials = 48,
|
||||
CryptographicProviders = 49,
|
||||
DatabaseAuditSpecifications = 50,
|
||||
DatabaseEncryptionKeys = 51,
|
||||
DatabaseScopedCredentials = 52,
|
||||
Endpoints = 53,
|
||||
ErrorMessages = 54,
|
||||
EventNotifications = 55,
|
||||
EventSessions = 56,
|
||||
LinkedServerLogins = 57,
|
||||
LinkedServers = 58,
|
||||
Logins = 59,
|
||||
MasterKeys = 60,
|
||||
Routes = 61,
|
||||
ServerAuditSpecifications = 62,
|
||||
ServerRoleMembership = 63,
|
||||
ServerRoles = 64,
|
||||
ServerTriggers = 65
|
||||
}
|
||||
|
||||
export enum ColumnType {
|
||||
text = 0,
|
||||
checkBox = 1,
|
||||
@@ -600,3 +686,9 @@ export enum NotebookChangeKind {
|
||||
Save = 2,
|
||||
CellExecuted = 3
|
||||
}
|
||||
|
||||
export type QueryEventType =
|
||||
| 'queryStart'
|
||||
| 'queryStop'
|
||||
| 'executionPlan'
|
||||
| 'visualize';
|
||||
|
||||
@@ -10,14 +10,14 @@ import {
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
|
||||
import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBase';
|
||||
import { IComponent, IComponentDescriptor, IModelStore } from 'sql/workbench/browser/modelComponents/interfaces';
|
||||
import { TitledComponent } from 'sql/workbench/browser/modelComponents/titledComponent';
|
||||
|
||||
@Component({
|
||||
selector: 'modelview-hyperlink',
|
||||
template: `<a [href]="getUrl()" target="blank">{{getLabel()}}</a>`
|
||||
template: `<a [href]="getUrl()" [title]="title" target="blank">{{getLabel()}}</a>`
|
||||
})
|
||||
export default class HyperlinkComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
|
||||
export default class HyperlinkComponent extends TitledComponent implements IComponent, OnDestroy, AfterViewInit {
|
||||
@Input() descriptor: IComponentDescriptor;
|
||||
@Input() modelStore: IModelStore;
|
||||
|
||||
|
||||
@@ -101,3 +101,7 @@ export interface IModelStore {
|
||||
*/
|
||||
validate(component: IComponent): Thenable<boolean>;
|
||||
}
|
||||
|
||||
export interface ITitledComponent {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
@@ -11,16 +11,16 @@ import {
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
|
||||
import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBase';
|
||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/workbench/browser/modelComponents/interfaces';
|
||||
import { SafeHtml, DomSanitizer } from '@angular/platform-browser';
|
||||
import { TitledComponent } from 'sql/workbench/browser/modelComponents/titledComponent';
|
||||
|
||||
@Component({
|
||||
selector: 'modelview-text',
|
||||
template: `
|
||||
<p [style.width]="getWidth()" [innerHTML]="getValue()" [ngStyle]="this.CSSStyles" (click)="onClick()"></p>`
|
||||
<p [style.width]="getWidth()" [innerHTML]="getValue()" [title]="title" [ngStyle]="this.CSSStyles" (click)="onClick()"></p>`
|
||||
})
|
||||
export default class TextComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
|
||||
export default class TextComponent extends TitledComponent implements IComponent, OnDestroy, AfterViewInit {
|
||||
@Input() descriptor: IComponentDescriptor;
|
||||
@Input() modelStore: IModelStore;
|
||||
|
||||
|
||||
29
src/sql/workbench/browser/modelComponents/titledComponent.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import {
|
||||
ChangeDetectorRef, ElementRef
|
||||
} from '@angular/core';
|
||||
|
||||
import { ITitledComponent } from 'sql/workbench/browser/modelComponents/interfaces';
|
||||
import * as azdata from 'azdata';
|
||||
import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBase';
|
||||
|
||||
|
||||
export abstract class TitledComponent extends ComponentBase implements ITitledComponent {
|
||||
|
||||
constructor(
|
||||
protected _changeRef: ChangeDetectorRef,
|
||||
protected _el: ElementRef) {
|
||||
super(_changeRef, _el);
|
||||
}
|
||||
|
||||
public get title(): string {
|
||||
return this.getPropertyOrDefault<azdata.HyperlinkComponentProperties, string>((props) => props.title, '');
|
||||
}
|
||||
|
||||
public set title(newTitle: string) {
|
||||
this.setPropertyFromUI<azdata.HyperlinkComponentProperties, string>((properties, title) => { properties.title = title; }, newTitle);
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,11 @@ import {
|
||||
RunQueryOnConnectionMode, IConnectionResult
|
||||
} from 'sql/platform/connection/common/connectionManagement';
|
||||
import { EditDataInput } from 'sql/workbench/parts/editData/browser/editDataInput';
|
||||
import { IRestoreDialogController } from 'sql/platform/restore/common/restoreService';
|
||||
import { IInsightsDialogService } from 'sql/workbench/services/insights/browser/insightsDialogService';
|
||||
import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/common/objectExplorerService';
|
||||
import { QueryInput } from 'sql/workbench/parts/query/common/queryInput';
|
||||
import { DashboardInput } from 'sql/workbench/parts/dashboard/browser/dashboardInput';
|
||||
import { ProfilerInput } from 'sql/workbench/parts/profiler/browser/profilerInput';
|
||||
import { IBackupUiService } from 'sql/workbench/services/backup/common/backupUiService';
|
||||
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IInsightsConfig } from 'sql/platform/dashboard/browser/insightRegistry';
|
||||
|
||||
@@ -9,7 +9,7 @@ import { IClipboardService } from 'sql/platform/clipboard/common/clipboardServic
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { IWindowsService, FileFilter } from 'vs/platform/windows/common/windows';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
@@ -152,7 +152,9 @@ export class SaveImageAction extends Action {
|
||||
|
||||
public async run(context: IChartActionContext): Promise<boolean> {
|
||||
if (context.insight instanceof Graph) {
|
||||
const filePath = await this.fileDialogService.pickFileToSave({});
|
||||
let fileFilters = new Array<FileFilter>({ extensions: ['png'], name: localize('resultsSerializer.saveAsFileExtensionPNGTitle', "PNG") });
|
||||
|
||||
const filePath = await this.fileDialogService.pickFileToSave({ filters: fileFilters });
|
||||
const data = (<Graph>context.insight).getCanvasData();
|
||||
if (!data) {
|
||||
this.notificationService.error(localize('chartNotFound', "Could not find chart to save"));
|
||||
|
||||
@@ -124,6 +124,9 @@ export abstract class JobManagementView extends TabChild implements AfterContent
|
||||
public refreshJobs() {
|
||||
this._agentViewComponent.refresh = true;
|
||||
}
|
||||
|
||||
public openLastNRun(notebook: azdata.AgentNotebookInfo, n: number, maxVisibleElements: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export interface JobActionContext {
|
||||
|
||||
@@ -441,6 +441,7 @@ notebookhistory-component
|
||||
height: 40px;
|
||||
background-size: 40px 40px;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vs-dark .notebook-grid-item > .img-error,
|
||||
|
||||
@@ -5,18 +5,17 @@
|
||||
|
||||
agentview-component {
|
||||
height: 100%;
|
||||
width : 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
jobsview-component,
|
||||
notebooksview-component {
|
||||
height: 100%;
|
||||
width : 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
.job-heading-container {
|
||||
height: 50px;
|
||||
border-bottom: 3px solid #f4f4f4;
|
||||
@@ -33,13 +32,13 @@ notebooksview-component {
|
||||
|
||||
.jobview-grid {
|
||||
height: calc(100% - 75px);
|
||||
width : 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.jobnotebooksview-grid {
|
||||
height: calc(100% - 75px);
|
||||
width : 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -53,13 +52,35 @@ notebooksview-component {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hc-black #jobsDiv jobsview-component .jobview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell,
|
||||
.hc-black #notebooksDiv notebooks-component .jobnotebooksview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
.hc-black
|
||||
#jobsDiv
|
||||
jobsview-component
|
||||
.jobview-grid
|
||||
.grid-canvas
|
||||
.ui-widget-content.slick-row
|
||||
.slick-cell,
|
||||
.hc-black
|
||||
#notebooksDiv
|
||||
notebooks-component
|
||||
.jobnotebooksview-grid
|
||||
.grid-canvas
|
||||
.ui-widget-content.slick-row
|
||||
.slick-cell {
|
||||
border: 1px solid #2b56f2;
|
||||
}
|
||||
|
||||
#jobsDiv jobsview-component .jobview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell,
|
||||
#notebooksDiv notebooksview-component .jobnotebooksview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
#jobsDiv
|
||||
jobsview-component
|
||||
.jobview-grid
|
||||
.grid-canvas
|
||||
.ui-widget-content.slick-row
|
||||
.slick-cell,
|
||||
#notebooksDiv
|
||||
notebooksview-component
|
||||
.jobnotebooksview-grid
|
||||
.grid-canvas
|
||||
.ui-widget-content.slick-row
|
||||
.slick-cell {
|
||||
border-right: transparent !important;
|
||||
border-left: transparent !important;
|
||||
line-height: 33px !important;
|
||||
@@ -103,8 +124,14 @@ notebooksview-component {
|
||||
}
|
||||
|
||||
#jobsDiv .jobview-grid .slick-cell.l1.r1.error-row .jobview-jobnametext,
|
||||
#notebooksDiv .jobnotebooksview-grid .slick-cell.l1.r1.error-row .jobview-jobnametext,
|
||||
#notebooksDiv .jobnotebooksview-grid .slick-cell.l1.r1.notebook-error-row .jobview-jobnametext {
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
.slick-cell.l1.r1.error-row
|
||||
.jobview-jobnametext,
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
.slick-cell.l1.r1.notebook-error-row
|
||||
.jobview-jobnametext {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -117,7 +144,10 @@ notebooksview-component {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#operatorsDiv .joboperatorsview-grid .slick-cell.l1.r1 .operatorview-operatornametext,
|
||||
#operatorsDiv
|
||||
.joboperatorsview-grid
|
||||
.slick-cell.l1.r1
|
||||
.operatorview-operatornametext,
|
||||
#alertsDiv .jobalertsview-grid .slick-cell.l1.r1 .alertview-alertnametext,
|
||||
#proxiesDiv .jobproxiesview-grid .slick-cell.l1.r1 .proxyview-proxynametext {
|
||||
text-overflow: ellipsis;
|
||||
@@ -132,8 +162,18 @@ notebooksview-component {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row .slick-cell.l1.r1.error-row,
|
||||
.jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row .slick-cell.l1.r1.error-row {
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
.slick-cell.l1.r1.error-row,
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
.slick-cell.l1.r1.error-row {
|
||||
width: 100%;
|
||||
opacity: 1;
|
||||
font-weight: 700;
|
||||
@@ -141,7 +181,12 @@ notebooksview-component {
|
||||
color: orangered;
|
||||
}
|
||||
|
||||
.jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row .slick-cell.l1.r1.notebook-error-row {
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
.slick-cell.l1.r1.notebook-error-row {
|
||||
width: 100%;
|
||||
opacity: 1;
|
||||
font-weight: 700;
|
||||
@@ -150,9 +195,24 @@ notebooksview-component {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row .slick-cell._detail_selector.error-row,
|
||||
.jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row .slick-cell._detail_selector.error-row,
|
||||
.jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row .slick-cell._detail_selector.notebook-error-row {
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
.slick-cell._detail_selector.error-row,
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
.slick-cell._detail_selector.error-row,
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
.slick-cell._detail_selector.notebook-error-row {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -192,7 +252,7 @@ notebooksview-component {
|
||||
|
||||
#jobsDiv .detail,
|
||||
#notebooksDiv .detail {
|
||||
padding: 5px
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#jobsDiv .preload,
|
||||
@@ -202,69 +262,83 @@ notebooksview-component {
|
||||
|
||||
#jobsDiv .dynamic-cell-detail > :first-child,
|
||||
#notebooksDiv .dynamic-cell-detail > :first-child {
|
||||
vertical-align: middle;
|
||||
line-height: 13px;
|
||||
padding: 10px;
|
||||
margin-left: 20px;
|
||||
vertical-align: middle;
|
||||
line-height: 13px;
|
||||
padding: 10px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.jobsview-icon {
|
||||
background-image: url('./job.svg');
|
||||
background-image: url("./job.svg");
|
||||
}
|
||||
|
||||
|
||||
.vs-dark .jobsview-icon,
|
||||
.hc-black .jobsview-icon {
|
||||
background-image: url('./job_inverse.svg');
|
||||
background-image: url("./job_inverse.svg");
|
||||
}
|
||||
|
||||
|
||||
.notebooksview-icon {
|
||||
background-image: url('./notebook.svg');
|
||||
background-image: url("./notebook.svg");
|
||||
}
|
||||
|
||||
.vs-dark .notebooksview-icon,
|
||||
.hc-black .notebooksview-icon {
|
||||
background-image: url('./notebook_inverse.svg');
|
||||
background-image: url("./notebook_inverse.svg");
|
||||
}
|
||||
|
||||
.alertsview-icon {
|
||||
background-image: url('./alert.svg');
|
||||
background-image: url("./alert.svg");
|
||||
}
|
||||
|
||||
.vs-dark .alertsview-icon,
|
||||
.hc-black .alertsview-icon {
|
||||
background-image: url('./alert_inverse.svg');
|
||||
background-image: url("./alert_inverse.svg");
|
||||
}
|
||||
|
||||
.proxiesview-icon {
|
||||
background-image: url('./proxy.svg');
|
||||
background-image: url("./proxy.svg");
|
||||
}
|
||||
|
||||
.vs-dark .proxiesview-icon,
|
||||
.hc-black .proxiesview-icon {
|
||||
background-image: url('./proxy_inverse.svg');
|
||||
background-image: url("./proxy_inverse.svg");
|
||||
}
|
||||
|
||||
.operatorsview-icon {
|
||||
background-image: url('./operator.svg');
|
||||
background-image: url("./operator.svg");
|
||||
}
|
||||
|
||||
.vs-dark .operatorsview-icon,
|
||||
.hc-black .operatorsview-icon {
|
||||
background-image: url('./operator_inverse.svg');
|
||||
background-image: url("./operator_inverse.svg");
|
||||
}
|
||||
|
||||
agentview-component .jobview-grid .grid-canvas > .ui-widget-content.slick-row.even > .slick-cell,
|
||||
agentview-component .jobnotebooksview-grid .grid-canvas > .ui-widget-content.slick-row.odd > .slick-cell {
|
||||
agentview-component
|
||||
.jobview-grid
|
||||
.grid-canvas
|
||||
> .ui-widget-content.slick-row.even
|
||||
> .slick-cell,
|
||||
agentview-component
|
||||
.jobnotebooksview-grid
|
||||
.grid-canvas
|
||||
> .ui-widget-content.slick-row.odd
|
||||
> .slick-cell {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vs-dark .jobview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
.vs-dark
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-header-columns
|
||||
.slick-resizable-handle {
|
||||
border-left: 1px dotted white;
|
||||
}
|
||||
|
||||
.hc-black .jobview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
.hc-black
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-header-columns
|
||||
.slick-resizable-handle {
|
||||
border-left: 1px dotted #2b56f2;
|
||||
}
|
||||
|
||||
@@ -279,47 +353,188 @@ agentview-component .jobnotebooksview-grid .grid-canvas > .ui-widget-content.sli
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
#jobsDiv jobsview-component .jobview-grid .slick-cell.l1.r1.error-row td.jobview-jobnameindicatorfailure,
|
||||
#notebooksDiv notebooksview-component .jobnotebooksview-grid .slick-cell.l1.r1.error-row td.jobview-jobnameindicatorfailure,
|
||||
#notebooksDiv notebooksview-component .jobnotebooksview-grid .slick-cell.l1.r1.notebook-error-row td.jobview-jobnameindicatorfailure {
|
||||
#jobsDiv
|
||||
jobsview-component
|
||||
.jobview-grid
|
||||
.slick-cell.l1.r1.error-row
|
||||
td.jobview-jobnameindicatorfailure,
|
||||
#notebooksDiv
|
||||
notebooksview-component
|
||||
.jobnotebooksview-grid
|
||||
.slick-cell.l1.r1.error-row
|
||||
td.jobview-jobnameindicatorfailure,
|
||||
#notebooksDiv
|
||||
notebooksview-component
|
||||
.jobnotebooksview-grid
|
||||
.slick-cell.l1.r1.notebook-error-row
|
||||
td.jobview-jobnameindicatorfailure {
|
||||
width: 0;
|
||||
background: none;
|
||||
}
|
||||
|
||||
#jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
#jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
#jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row> .slick-cell.hovered,
|
||||
#notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
#notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
#notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row> .slick-cell.hovered {
|
||||
#jobsDiv
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
#jobsDiv
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell,
|
||||
#jobsDiv
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered,
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell,
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered {
|
||||
background: #dcdcdc !important;
|
||||
}
|
||||
|
||||
.vs-dark #jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.vs-dark #jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.vs-dark #jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
.vs-dark #notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.vs-dark #notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.vs-dark #notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell {
|
||||
.vs-dark
|
||||
#jobsDiv
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
.vs-dark
|
||||
#jobsDiv
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered,
|
||||
.vs-dark
|
||||
#jobsDiv
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell,
|
||||
.vs-dark
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
.vs-dark
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered,
|
||||
.vs-dark
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell {
|
||||
background: #444444 !important;
|
||||
}
|
||||
|
||||
.hc-black #jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.hc-black #jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.hc-black #jobsDiv .jobview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
.hc-black #notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.hc-black #notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.hc-black #notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell {
|
||||
.hc-black
|
||||
#jobsDiv
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
.hc-black
|
||||
#jobsDiv
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered,
|
||||
.hc-black
|
||||
#jobsDiv
|
||||
.jobview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell,
|
||||
.hc-black
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
.hc-black
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered,
|
||||
.hc-black
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell {
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
table.jobprevruns div.bar0, table.jobprevruns div.bar1, table.jobprevruns div.bar2,
|
||||
table.jobprevruns div.bar3, table.jobprevruns div.bar4, table.jobprevruns div.bar5 {
|
||||
table.jobprevruns div.bar,
|
||||
table.jobprevruns div.bar0,
|
||||
table.jobprevruns div.bar1,
|
||||
table.jobprevruns div.bar2,
|
||||
table.jobprevruns div.bar3,
|
||||
table.jobprevruns div.bar4,
|
||||
table.jobprevruns div.bar5 {
|
||||
padding-top: 3px;
|
||||
padding-left: 5px;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
table.jobprevruns div.bar {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.jobview-grid .slick-cell.l10.r10,
|
||||
.jobnotebooksview-grid .slick-cell.l10.r10 {
|
||||
text-align: center;
|
||||
@@ -336,51 +551,51 @@ table.jobprevruns > tbody {
|
||||
|
||||
#notebooksDiv .jobnotebooksview-grid {
|
||||
height: calc(100% - 75px);
|
||||
width : 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#alertsDiv .jobalertsview-grid {
|
||||
height: calc(100% - 75px);
|
||||
width : 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#operatorsDiv .joboperatorsview-grid {
|
||||
height: calc(100% - 75px);
|
||||
width : 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#proxiesDiv .jobproxiesview-grid {
|
||||
height: calc(100% - 75px);
|
||||
width : 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.vs .action-label.icon.refreshIcon {
|
||||
background-image: url('refresh.svg');
|
||||
background-image: url("refresh.svg");
|
||||
}
|
||||
|
||||
.vs-dark .action-label.icon.refreshIcon,
|
||||
.hc-black .action-label.icon.refreshIcon {
|
||||
background-image: url('refresh_inverse.svg');
|
||||
.hc-black .action-label.icon.refreshIcon {
|
||||
background-image: url("refresh_inverse.svg");
|
||||
}
|
||||
|
||||
|
||||
.vs .action-label.icon.openNotebook {
|
||||
background-image: url('open_notebook.svg');
|
||||
background-image: url("open_notebook.svg");
|
||||
}
|
||||
|
||||
.vs-dark .action-label.icon.openNotebook,
|
||||
.hc-black .action-label.icon.openNotebook {
|
||||
background-image: url('open_notebook_inverse.svg');
|
||||
.hc-black .action-label.icon.openNotebook {
|
||||
background-image: url("open_notebook_inverse.svg");
|
||||
}
|
||||
|
||||
.agent-actionbar-container .monaco-action-bar > ul.actions-container > li.action-item {
|
||||
.agent-actionbar-container
|
||||
.monaco-action-bar
|
||||
> ul.actions-container
|
||||
> li.action-item {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
@@ -390,107 +605,311 @@ notebooksview-component .jobnotebooksview-grid .slick-cell.notebook-error-row {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#notebooksDiv notebooksview-component .jobnotebooksview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
#notebooksDiv
|
||||
notebooksview-component
|
||||
.jobnotebooksview-grid
|
||||
.grid-canvas
|
||||
.ui-widget-content.slick-row
|
||||
.slick-cell {
|
||||
border-right: transparent !important;
|
||||
border-left: transparent !important;
|
||||
line-height: 33px !important;
|
||||
}
|
||||
|
||||
#notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
#notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
#notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row> .slick-cell.hovered {
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell,
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered {
|
||||
background: #dcdcdc !important;
|
||||
}
|
||||
|
||||
.vs-dark #notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.vs-dark #notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.vs-dark #notebooksDiv .jobnotebooksview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell {
|
||||
.vs-dark
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
.vs-dark
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered,
|
||||
.vs-dark
|
||||
#notebooksDiv
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell {
|
||||
background: #444444 !important;
|
||||
}
|
||||
|
||||
.vs-dark .jobnotebooksview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
.vs-dark
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-header-columns
|
||||
.slick-resizable-handle {
|
||||
border-left: 1px dotted white;
|
||||
}
|
||||
|
||||
.jobnotebooksview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
.jobnotebooksview-grid
|
||||
> .monaco-table
|
||||
.slick-header-columns
|
||||
.slick-resizable-handle {
|
||||
border-left: 1px dotted #444444;
|
||||
}
|
||||
|
||||
#alertsDiv jobalertsview-component .jobalertsview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
#alertsDiv
|
||||
jobalertsview-component
|
||||
.jobalertsview-grid
|
||||
.grid-canvas
|
||||
.ui-widget-content.slick-row
|
||||
.slick-cell {
|
||||
border-right: transparent !important;
|
||||
border-left: transparent !important;
|
||||
line-height: 33px !important;
|
||||
}
|
||||
|
||||
#alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
#alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
#alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row> .slick-cell.hovered {
|
||||
#alertsDiv
|
||||
.jobalertsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
#alertsDiv
|
||||
.jobalertsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell,
|
||||
#alertsDiv
|
||||
.jobalertsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered {
|
||||
background: #dcdcdc !important;
|
||||
}
|
||||
|
||||
.vs-dark #alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.vs-dark #alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.vs-dark #alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell {
|
||||
.vs-dark
|
||||
#alertsDiv
|
||||
.jobalertsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
.vs-dark
|
||||
#alertsDiv
|
||||
.jobalertsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered,
|
||||
.vs-dark
|
||||
#alertsDiv
|
||||
.jobalertsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell {
|
||||
background: #444444 !important;
|
||||
}
|
||||
|
||||
.vs-dark .jobalertsview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
.vs-dark
|
||||
.jobalertsview-grid
|
||||
> .monaco-table
|
||||
.slick-header-columns
|
||||
.slick-resizable-handle {
|
||||
border-left: 1px dotted white;
|
||||
}
|
||||
|
||||
.jobalertsview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
.jobalertsview-grid
|
||||
> .monaco-table
|
||||
.slick-header-columns
|
||||
.slick-resizable-handle {
|
||||
border-left: 1px dotted #444444;
|
||||
}
|
||||
|
||||
#operatorsDiv joboperatorsview-component .joboperatorsview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
#operatorsDiv
|
||||
joboperatorsview-component
|
||||
.joboperatorsview-grid
|
||||
.grid-canvas
|
||||
.ui-widget-content.slick-row
|
||||
.slick-cell {
|
||||
border-right: transparent !important;
|
||||
border-left: transparent !important;
|
||||
line-height: 33px !important;
|
||||
}
|
||||
|
||||
#operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
#operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
#operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row> .slick-cell.hovered {
|
||||
#operatorsDiv
|
||||
.joboperatorsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
#operatorsDiv
|
||||
.joboperatorsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell,
|
||||
#operatorsDiv
|
||||
.joboperatorsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered {
|
||||
background: #dcdcdc !important;
|
||||
}
|
||||
|
||||
.vs-dark #operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.vs-dark #operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.vs-dark #operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell {
|
||||
.vs-dark
|
||||
#operatorsDiv
|
||||
.joboperatorsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
.vs-dark
|
||||
#operatorsDiv
|
||||
.joboperatorsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered,
|
||||
.vs-dark
|
||||
#operatorsDiv
|
||||
.joboperatorsview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell {
|
||||
background: #444444 !important;
|
||||
}
|
||||
|
||||
.vs-dark .joboperatorsview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
.vs-dark
|
||||
.joboperatorsview-grid
|
||||
> .monaco-table
|
||||
.slick-header-columns
|
||||
.slick-resizable-handle {
|
||||
border-left: 1px dotted white;
|
||||
}
|
||||
|
||||
.joboperatorsview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
.joboperatorsview-grid
|
||||
> .monaco-table
|
||||
.slick-header-columns
|
||||
.slick-resizable-handle {
|
||||
border-left: 1px dotted #444444;
|
||||
}
|
||||
|
||||
#proxiesDiv jobproxiesview-component .jobproxiesview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
#proxiesDiv
|
||||
jobproxiesview-component
|
||||
.jobproxiesview-grid
|
||||
.grid-canvas
|
||||
.ui-widget-content.slick-row
|
||||
.slick-cell {
|
||||
border-right: transparent !important;
|
||||
border-left: transparent !important;
|
||||
line-height: 33px !important;
|
||||
}
|
||||
|
||||
#proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
#proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
#proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row> .slick-cell.hovered {
|
||||
#proxiesDiv
|
||||
.jobproxiesview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
#proxiesDiv
|
||||
.jobproxiesview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell,
|
||||
#proxiesDiv
|
||||
.jobproxiesview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered {
|
||||
background: #dcdcdc !important;
|
||||
}
|
||||
|
||||
.vs-dark #proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.vs-dark #proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.vs-dark #proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell {
|
||||
.vs-dark
|
||||
#proxiesDiv
|
||||
.jobproxiesview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row:hover
|
||||
> .slick-cell,
|
||||
.vs-dark
|
||||
#proxiesDiv
|
||||
.jobproxiesview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row
|
||||
> .slick-cell.hovered,
|
||||
.vs-dark
|
||||
#proxiesDiv
|
||||
.jobproxiesview-grid
|
||||
> .monaco-table
|
||||
.slick-viewport
|
||||
> .grid-canvas
|
||||
> .ui-widget-content.slick-row.hovered
|
||||
> .slick-cell {
|
||||
background: #444444 !important;
|
||||
}
|
||||
|
||||
.vs-dark .jobproxiesview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
.vs-dark
|
||||
.jobproxiesview-grid
|
||||
> .monaco-table
|
||||
.slick-header-columns
|
||||
.slick-resizable-handle {
|
||||
border-left: 1px dotted white;
|
||||
}
|
||||
|
||||
.jobproxiesview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
.jobproxiesview-grid
|
||||
> .monaco-table
|
||||
.slick-header-columns
|
||||
.slick-resizable-handle {
|
||||
border-left: 1px dotted #444444;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<div class="jobhistory-heading-container">
|
||||
<h1 class="job-heading">Notebook | {{ this._agentNotebookInfo?.name }}</h1>
|
||||
<h1 class="job-heading">Notebook Jobs| {{ this._agentNotebookInfo?.name }}</h1>
|
||||
<div class="icon in-progress" *ngIf="showProgressWheel()"></div>
|
||||
</div>
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
|
||||
<!-- Overview -->
|
||||
<div class="overview-container">
|
||||
<div class="overview-tab" (click)="toggleCollapse()" tabindex="0">
|
||||
<div class="overview-tab" (click)="toggleCollapse()">
|
||||
<input id="accordion" type="checkbox" />
|
||||
<label for="accordion">
|
||||
<label for="accordion" tabindex="0">
|
||||
<div
|
||||
class="resultsViewCollapsible collapsed"
|
||||
(click)="toggleCollapse()"
|
||||
@@ -48,10 +48,10 @@
|
||||
{{ this._agentNotebookInfo?.targetDatabase }}
|
||||
</td>
|
||||
<td id="col3">
|
||||
Enabled:
|
||||
Has Schedule:
|
||||
</td>
|
||||
<td id="col4">
|
||||
{{ this._agentNotebookInfo?.enabled }}
|
||||
{{ this._agentNotebookInfo?.hasSchedule }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -81,11 +81,10 @@
|
||||
<div
|
||||
class="overview-tab"
|
||||
(click)="toggleGridCollapse(i)"
|
||||
tabindex="{{i}}"
|
||||
*ngIf="grid.histories?.length"
|
||||
>
|
||||
<input id="accordion{{ i }}" type="checkbox" class="grid-arrow" />
|
||||
<label for="accordion{{ i }}">
|
||||
<input id="accordion{{ i }}" type="checkbox" class="grid-arrow"/>
|
||||
<label for="accordion{{ i }}" tabindex="0">
|
||||
<div id= "history-grid-icon{{i}}" (click)="toggleGridCollapse(i)"
|
||||
class="resultsViewCollapsible"></div>
|
||||
{{ grid.title }}
|
||||
@@ -94,11 +93,13 @@
|
||||
<div
|
||||
*ngFor="let history of grid.histories"
|
||||
class="notebook-grid-item"
|
||||
tabindex="0"
|
||||
(dblclick)="openNotebook(history)"
|
||||
title="{{ createdTooltip(history) }}"
|
||||
(contextmenu)="
|
||||
openHistoryContextMenu($event, history, grid.contextMenuType)
|
||||
"
|
||||
(keydown.enter)="openNotebook(history)"
|
||||
>
|
||||
<div
|
||||
*ngIf="history.materializedNotebookErrorInfo"
|
||||
|
||||
@@ -14,7 +14,7 @@ import { Table } from 'sql/base/browser/ui/table/table';
|
||||
import { AgentViewComponent } from 'sql/workbench/parts/jobManagement/browser/agentView.component';
|
||||
import { RowDetailView } from 'sql/base/browser/ui/table/plugins/rowDetailView';
|
||||
import { NotebookCacheObject } from 'sql/platform/jobManagement/common/jobManagementService';
|
||||
import { EditJobAction, NewNotebookJobAction, RunJobAction, EditNotebookJobAction, JobsRefreshAction, IJobActionInfo, DeleteNotebookAction } from 'sql/platform/jobManagement/browser/jobActions';
|
||||
import { EditJobAction, NewNotebookJobAction, RunJobAction, EditNotebookJobAction, JobsRefreshAction, IJobActionInfo, DeleteNotebookAction, OpenLatestRunMaterializedNotebook } from 'sql/platform/jobManagement/browser/jobActions';
|
||||
import { JobManagementUtilities } from 'sql/platform/jobManagement/browser/jobManagementUtilities';
|
||||
import { HeaderFilter } from 'sql/base/browser/ui/table/plugins/headerFilter.plugin';
|
||||
import { IJobManagementService } from 'sql/platform/jobManagement/common/interfaces';
|
||||
@@ -395,6 +395,22 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit,
|
||||
this.highlightErrorRows(e1), (e2) => this.hightlightNonErrorRows(e2));
|
||||
});
|
||||
|
||||
jQuery('.bar').click((e) => {
|
||||
let clickEventTarget = e.target;
|
||||
let barId = Number(clickEventTarget.id.replace('bar', ''));
|
||||
let jobId = clickEventTarget.parentElement.offsetParent.id.replace('notebook', '');
|
||||
let notebooks = this._notebookCacheObject.notebooks;
|
||||
let targetNotebook: azdata.AgentNotebookInfo;
|
||||
for (let i = 0; i < notebooks.length; i++) {
|
||||
if (jobId === notebooks[i].jobId) {
|
||||
targetNotebook = notebooks[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.openLastNRun(targetNotebook, barId, 5);
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
// cache the dataview for future use
|
||||
this._notebookCacheObject.dataView = this.dataView;
|
||||
this.filterValueMap['start'] = [[], this.dataView.getItems()];
|
||||
@@ -540,21 +556,21 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit,
|
||||
if (runChart && runChart.length > 0) {
|
||||
return `<table class="jobprevruns" id="${dataContext.id}">
|
||||
<tr>
|
||||
<td>${runChart[0] ? runChart[0] : '<div class="bar0"></div>'}</td>
|
||||
<td>${runChart[1] ? runChart[1] : '<div class="bar1"></div>'}</td>
|
||||
<td>${runChart[2] ? runChart[2] : '<div class="bar2"></div>'}</td>
|
||||
<td>${runChart[3] ? runChart[3] : '<div class="bar3"></div>'}</td>
|
||||
<td>${runChart[4] ? runChart[4] : '<div class="bar4"></div>'}</td>
|
||||
<td>${runChart[0] ? runChart[0] : '<div class="bar" id="bar0"></div>'}</td>
|
||||
<td>${runChart[1] ? runChart[1] : '<div class="bar" id="bar1"></div>'}</td>
|
||||
<td>${runChart[2] ? runChart[2] : '<div class="bar" id="bar2"></div>'}</td>
|
||||
<td>${runChart[3] ? runChart[3] : '<div class="bar" id="bar3"></div>'}</td>
|
||||
<td>${runChart[4] ? runChart[4] : '<div class="bar" id="bar4"></div>'}</td>
|
||||
</tr>
|
||||
</table>`;
|
||||
} else {
|
||||
return `<table class="jobprevruns" id="${dataContext.id}">
|
||||
<tr>
|
||||
<td><div class="bar0"></div></td>
|
||||
<td><div class="bar1"></div></td>
|
||||
<td><div class="bar2"></div></td>
|
||||
<td><div class="bar3"></div></td>
|
||||
<td><div class="bar4"></div></td>
|
||||
<td><div class="bar" id="bar0"></div></td>
|
||||
<td><div class="bar" id="bar1"></div></td>
|
||||
<td><div class="bar" id="bar2"></div></td>
|
||||
<td><div class="bar" id="bar3"></div></td>
|
||||
<td><div class="bar" id="bar4"></div></td>
|
||||
</tr>
|
||||
</table>`;
|
||||
}
|
||||
@@ -667,7 +683,7 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit,
|
||||
if (jobHistories[i].materializedNotebookErrorInfo !== null && jobHistories[i].materializedNotebookErrorInfo.length > 0) {
|
||||
bgColor = 'orange';
|
||||
}
|
||||
let runGraph = jQuery(`table.jobprevruns#${jobId} > tbody > tr > td > div.bar${i}`);
|
||||
let runGraph = jQuery(`table.jobprevruns#${jobId} > tbody > tr > td > #bar${i}`);
|
||||
if (runGraph.length > 0) {
|
||||
|
||||
runGraph.css('height', chartHeights[i]);
|
||||
@@ -884,10 +900,11 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit,
|
||||
const editAction = this._instantiationService.createInstance(EditJobAction);
|
||||
const editNotebookAction = this._instantiationService.createInstance(EditNotebookJobAction);
|
||||
const runJobAction = this._instantiationService.createInstance(RunJobAction);
|
||||
const openLatestRunAction = this._instantiationService.createInstance(OpenLatestRunMaterializedNotebook);
|
||||
return [
|
||||
runJobAction,
|
||||
openLatestRunAction,
|
||||
editNotebookAction,
|
||||
editAction,
|
||||
this._instantiationService.createInstance(DeleteNotebookAction)
|
||||
];
|
||||
}
|
||||
@@ -981,4 +998,31 @@ export class NotebooksViewComponent extends JobManagementView implements OnInit,
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
await this._commandService.executeCommand('agent.openNotebookDialog', ownerUri);
|
||||
}
|
||||
|
||||
public async openLastNRun(notebook: azdata.AgentNotebookInfo, n: number, maxVisibleElements: number) {
|
||||
let notebookHistories = this._notebookCacheObject.getNotebookHistory(notebook.jobId);
|
||||
if (notebookHistories && n < notebookHistories.length) {
|
||||
notebookHistories = notebookHistories.sort((h1, h2) => {
|
||||
return new Date(h2.runDate).getTime() - new Date(h1.runDate).getTime();
|
||||
});
|
||||
if (notebookHistories.length > maxVisibleElements) {
|
||||
n = notebookHistories.length - (maxVisibleElements - n);
|
||||
}
|
||||
n = notebookHistories.length - 1 - n;
|
||||
let history: azdata.AgentNotebookHistoryInfo = notebookHistories[n];
|
||||
// Did Job Fail? if yes, then notebook to return
|
||||
if (history.runStatus === 0) {
|
||||
return;
|
||||
}
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
let targetDatabase = notebook.targetDatabase;
|
||||
const result = await this._jobManagementService.getMaterialziedNotebook(ownerUri, targetDatabase, history.materializedNotebookId);
|
||||
if (result) {
|
||||
let regex = /:|-/gi;
|
||||
let readableDataTimeString = history.runDate.replace(regex, '').replace(' ', '');
|
||||
let tempNotebookFileName = notebook.name + '_' + readableDataTimeString;
|
||||
await this._commandService.executeCommand('agent.openNotebookEditorFromJsonString', tempNotebookFileName, result.notebookMaterialized);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,10 +341,17 @@ export class NotebookInput extends EditorInput {
|
||||
} else {
|
||||
let textOrUntitledEditorModel: UntitledEditorModel | IEditorModel;
|
||||
if (this.resource.scheme === Schemas.untitled) {
|
||||
textOrUntitledEditorModel = this._untitledEditorModel ? this._untitledEditorModel : await this._textInput.resolve();
|
||||
}
|
||||
else {
|
||||
if (this._untitledEditorModel) {
|
||||
this._untitledEditorModel.textEditorModel.onBeforeAttached();
|
||||
textOrUntitledEditorModel = this._untitledEditorModel;
|
||||
} else {
|
||||
let resolvedInput = await this._textInput.resolve();
|
||||
resolvedInput.textEditorModel.onBeforeAttached();
|
||||
textOrUntitledEditorModel = resolvedInput;
|
||||
}
|
||||
} else {
|
||||
const textEditorModelReference = await this.textModelService.createModelReference(this.resource);
|
||||
textEditorModelReference.object.textEditorModel.onBeforeAttached();
|
||||
textOrUntitledEditorModel = await textEditorModelReference.object.load();
|
||||
}
|
||||
this._model = this.instantiationService.createInstance(NotebookEditorModel, this.resource, textOrUntitledEditorModel);
|
||||
@@ -385,6 +392,9 @@ export class NotebookInput extends EditorInput {
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this._model) {
|
||||
this._model.editorModel.textEditorModel.onBeforeDetached();
|
||||
}
|
||||
this._disposeContainer();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -39,11 +39,60 @@ export class NotebookTextFileModel {
|
||||
// convert the range to leverage offsets in the json
|
||||
if (contentChange && contentChange.modelContentChangedEvent && areRangePropertiesPopulated(cellGuidRange)) {
|
||||
contentChange.modelContentChangedEvent.changes.forEach(change => {
|
||||
// When writing to JSON we need to escape double quotes and backslashes
|
||||
let textEscapedQuotesAndBackslashes = change.text.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||
|
||||
let startLineNumber = change.range.startLineNumber + cellGuidRange.startLineNumber - 1;
|
||||
let endLineNumber = change.range.endLineNumber + cellGuidRange.startLineNumber - 1;
|
||||
let startLineText = textEditorModel.textEditorModel.getLineContent(startLineNumber);
|
||||
let endLineText = textEditorModel.textEditorModel.getLineContent(endLineNumber);
|
||||
|
||||
/* This gets the text on the start and end lines of the range where we'll be inserting text. We need to convert the escaped strings to unescaped strings.
|
||||
Example:
|
||||
|
||||
Previous state
|
||||
EDITOR:
|
||||
""""
|
||||
|
||||
TEXTEDITORMODEL:
|
||||
' "\"\"\"\""'
|
||||
|
||||
Now, user wants to insert text after the 4 double quotes, like so:
|
||||
EDITOR:
|
||||
""""sample text
|
||||
|
||||
TEXTEDITORMODEL (result):
|
||||
' "\"\"\"\"sample text"'
|
||||
|
||||
Notice that we don't have a 1:1 mapping for characters from the editor to the text editor model, because the double quotes need to be escaped
|
||||
(the same is true for backslashes).
|
||||
|
||||
Therefore, we need to determine (at both the start and end lines) the "real" start and end columns in the text editor model by counting escaped characters.
|
||||
|
||||
We do this by doing the following:
|
||||
- Start with (escaped) text in the text editor model
|
||||
- Unescape this text
|
||||
- Get a substring of that text from the column in JSON until the change's startColumn (starting from the first " in the text editor model)
|
||||
- Escape this substring
|
||||
- Leverage the substring's length to calculate the "real" start/end columns
|
||||
*/
|
||||
let unescapedStartSubstring = startLineText.replace(/\\"/g, '"').replace(/\\\\/g, '\\').substr(cellGuidRange.startColumn, change.range.startColumn - 1);
|
||||
let unescapedEndSubstring = endLineText.replace(/\\"/g, '"').replace(/\\\\/g, '\\').substr(cellGuidRange.startColumn, change.range.endColumn - 1);
|
||||
|
||||
// now we have the portion before the text to be inserted for both the start and end lines
|
||||
// so next step is to escape " and \
|
||||
|
||||
let escapedStartSubstring = unescapedStartSubstring.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||
let escapedEndSubstring = unescapedEndSubstring.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||
|
||||
let computedStartColumn = escapedStartSubstring.length + cellGuidRange.startColumn + 1;
|
||||
let computedEndColumn = escapedEndSubstring.length + cellGuidRange.startColumn + 1;
|
||||
|
||||
let convertedRange: IRange = {
|
||||
startLineNumber: change.range.startLineNumber + cellGuidRange.startLineNumber - 1,
|
||||
endLineNumber: change.range.endLineNumber + cellGuidRange.startLineNumber - 1,
|
||||
startColumn: change.range.startColumn + cellGuidRange.startColumn,
|
||||
endColumn: change.range.endColumn + cellGuidRange.startColumn
|
||||
startLineNumber: startLineNumber,
|
||||
endLineNumber: endLineNumber,
|
||||
startColumn: computedStartColumn,
|
||||
endColumn: computedEndColumn
|
||||
};
|
||||
// Need to subtract one because we're going from 1-based to 0-based
|
||||
let startSpaces: string = ' '.repeat(cellGuidRange.startColumn - 1);
|
||||
@@ -52,13 +101,12 @@ export class NotebookTextFileModel {
|
||||
// this is another string
|
||||
textEditorModel.textEditorModel.applyEdits([{
|
||||
range: new Range(convertedRange.startLineNumber, convertedRange.startColumn, convertedRange.endLineNumber, convertedRange.endColumn),
|
||||
text: change.text.split(this._eol).join('\\n\",'.concat(this._eol).concat(startSpaces).concat('\"'))
|
||||
text: textEscapedQuotesAndBackslashes.split(/[\r\n]+/gm).join('\\n\",'.concat(this._eol).concat(startSpaces).concat('\"'))
|
||||
}]);
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public transformAndApplyEditForOutputUpdate(contentChange: NotebookContentChange, textEditorModel: TextFileEditorModel | UntitledEditorModel): boolean {
|
||||
@@ -69,17 +117,23 @@ export class NotebookTextFileModel {
|
||||
} else {
|
||||
newOutput = '\n'.concat(newOutput).concat('\n');
|
||||
}
|
||||
let range = this.getEndOfOutputs(textEditorModel, contentChange.cells[0].cellGuid);
|
||||
if (range) {
|
||||
|
||||
// Execution count will always be after the end of the outputs in JSON. This is a sanity mechanism.
|
||||
let executionCountMatch = this.getExecutionCountRange(textEditorModel, contentChange.cells[0].cellGuid);
|
||||
if (!executionCountMatch || !executionCountMatch.range) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let endOutputsRange = this.getEndOfOutputs(textEditorModel, contentChange.cells[0].cellGuid);
|
||||
if (endOutputsRange && endOutputsRange.startLineNumber < executionCountMatch.range.startLineNumber) {
|
||||
textEditorModel.textEditorModel.applyEdits([{
|
||||
range: new Range(range.startLineNumber, range.startColumn, range.startLineNumber, range.startColumn),
|
||||
range: new Range(endOutputsRange.startLineNumber, endOutputsRange.startColumn, endOutputsRange.startLineNumber, endOutputsRange.startColumn),
|
||||
text: newOutput
|
||||
}]);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public transformAndApplyEditForCellUpdated(contentChange: NotebookContentChange, textEditorModel: TextFileEditorModel | UntitledEditorModel): boolean {
|
||||
@@ -111,9 +165,7 @@ export class NotebookTextFileModel {
|
||||
if (!textEditorModel || !contentChange || !contentChange.cells || !contentChange.cells[0] || !contentChange.cells[0].cellGuid) {
|
||||
return false;
|
||||
}
|
||||
if (!this.getOutputNodeByGuid(textEditorModel, contentChange.cells[0].cellGuid)) {
|
||||
this.updateOutputBeginRange(textEditorModel, contentChange.cells[0].cellGuid);
|
||||
}
|
||||
this.updateOutputBeginRange(textEditorModel, contentChange.cells[0].cellGuid);
|
||||
let outputEndRange = this.getEndOfOutputs(textEditorModel, contentChange.cells[0].cellGuid);
|
||||
let outputStartRange = this.getOutputNodeByGuid(textEditorModel, contentChange.cells[0].cellGuid);
|
||||
if (outputStartRange && outputEndRange) {
|
||||
@@ -247,7 +299,7 @@ export class NotebookTextFileModel {
|
||||
}
|
||||
|
||||
function areRangePropertiesPopulated(range: Range) {
|
||||
return range && range.startLineNumber && range.startColumn && range.endLineNumber && range.endColumn;
|
||||
return range && range.startLineNumber !== 0 && range.startColumn !== 0 && range.endLineNumber !== 0 && range.endColumn !== 0;
|
||||
}
|
||||
|
||||
function findOrSetCellGuidMatch(textEditorModel: TextFileEditorModel | UntitledEditorModel, cellGuid: string): FindMatch[] {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ConnectionManagementService } from 'sql/platform/connection/common/conn
|
||||
import { CellModel } from 'sql/workbench/parts/notebook/common/models/cell';
|
||||
import { CellTypes, NotebookChangeType } from 'sql/workbench/parts/notebook/common/models/contracts';
|
||||
import { ModelFactory } from 'sql/workbench/parts/notebook/common/models/modelFactory';
|
||||
import { INotebookModelOptions, NotebookContentChange } from 'sql/workbench/parts/notebook/common/models/modelInterfaces';
|
||||
import { INotebookModelOptions, NotebookContentChange, ICellModel } from 'sql/workbench/parts/notebook/common/models/modelInterfaces';
|
||||
import { NotebookEditorModel } from 'sql/workbench/parts/notebook/browser/models/notebookInput';
|
||||
import { NotebookModel } from 'sql/workbench/parts/notebook/common/models/notebookModel';
|
||||
import { NotebookService } from 'sql/workbench/services/notebook/common/notebookServiceImpl';
|
||||
@@ -589,6 +589,66 @@ suite('Notebook Editor Model', function (): void {
|
||||
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
test('should not insert update at incorrect location', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
let notebookEditorModel = await createTextEditorModel(this);
|
||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||
|
||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||
|
||||
let contentChange: NotebookContentChange = {
|
||||
changeType: NotebookChangeType.CellsModified,
|
||||
cells: [newCell],
|
||||
cellIndex: 0
|
||||
};
|
||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(true);
|
||||
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(14)).equal(' "outputs": [');
|
||||
|
||||
// First update the model with unmatched brackets
|
||||
let newUnmatchedBracketOutput: nb.IStreamResult = { output_type: 'stream', name: 'stdout', text: '[0em' };
|
||||
newCell[<any>'_outputs'] = newCell.outputs.concat(newUnmatchedBracketOutput);
|
||||
|
||||
contentChange = {
|
||||
changeType: NotebookChangeType.CellOutputUpdated,
|
||||
cells: [newCell]
|
||||
};
|
||||
|
||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputUpdated);
|
||||
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(8)).equal(' "source": [');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(12)).equal(' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(14)).equal(' "outputs": [');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(26)).equal(' "text": "[0em"');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(27)).equal('}');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(28)).equal(' ],');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(29)).equal(' "execution_count": 0');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(30)).equal(' }');
|
||||
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
|
||||
// Now test updating the model after an unmatched bracket was previously output
|
||||
let newBracketlessOutput: nb.IStreamResult = { output_type: 'stream', name: 'stdout', text: 'test test test' };
|
||||
newCell[<any>'_outputs'] = newCell[<any>'_outputs'].concat(newBracketlessOutput);
|
||||
|
||||
contentChange = {
|
||||
changeType: NotebookChangeType.CellOutputUpdated,
|
||||
cells: [newCell]
|
||||
};
|
||||
|
||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellOutputUpdated);
|
||||
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(32)).equal(' "text": "test test test"');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(33)).equal(' }');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(34)).equal(' ],');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(35)).equal(' "execution_count": 0');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(36)).equal(' }');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(37)).equal(' ]');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(38)).equal('}');
|
||||
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(true);
|
||||
});
|
||||
|
||||
test('should not replace entire text model for output changes (1st update)', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
@@ -631,6 +691,170 @@ suite('Notebook Editor Model', function (): void {
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
|
||||
test('should not replace entire text model for content change with double quotes', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
let notebookEditorModel = await createTextEditorModel(this);
|
||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||
|
||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||
|
||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '"This text is in quotes"');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(9)).equal(' "\\"This text is in quotes\\""');
|
||||
|
||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
|
||||
test('should not replace entire text model for content change with many double quotes', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
let notebookEditorModel = await createTextEditorModel(this);
|
||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||
|
||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||
|
||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '""""""""""');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(9)).equal(' "\\"\\"\\"\\"\\"\\"\\"\\"\\"\\""');
|
||||
|
||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
|
||||
test('should not replace entire text model for content change with many backslashes', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
let notebookEditorModel = await createTextEditorModel(this);
|
||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||
|
||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||
|
||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '\\\\\\\\\\');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(9)).equal(' "\\\\\\\\\\\\\\\\\\\\\"');
|
||||
|
||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
|
||||
test('should not replace entire text model for content change with many backslashes and double quotes', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
let notebookEditorModel = await createTextEditorModel(this);
|
||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||
|
||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||
|
||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '\"\"\"\"\"\"\"\"\"\"');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(9)).equal(' "\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\"\\\""');
|
||||
|
||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
|
||||
test('should not replace entire text model for content change with no special characters', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
let notebookEditorModel = await createTextEditorModel(this);
|
||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||
|
||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||
|
||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, 'this is a long line in a cell test. Everything should serialize correctly! # Comments here: adding more tests is fun?');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(9)).equal(' "this is a long line in a cell test. Everything should serialize correctly! # Comments here: adding more tests is fun?"');
|
||||
|
||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
|
||||
test('should not replace entire text model for content change with variety of characters', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
let notebookEditorModel = await createTextEditorModel(this);
|
||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||
|
||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||
|
||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '`~1!2@3#4$5%6^7&8*9(0)-_=+[{]}\\|;:",<.>/?\'');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(9)).equal(' "`~1!2@3#4$5%6^7&8*9(0)-_=+[{]}\\\\|;:\\",<.>/?\'"');
|
||||
|
||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
|
||||
test('should not replace entire text model for content change with single quotes', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
let notebookEditorModel = await createTextEditorModel(this);
|
||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||
|
||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||
|
||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '\'\'\'\'');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(9)).equal(' "\'\'\'\'"');
|
||||
|
||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
|
||||
test('should not replace entire text model for content change with empty content', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
let notebookEditorModel = await createTextEditorModel(this);
|
||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||
|
||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||
|
||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(9)).equal(' ""');
|
||||
|
||||
ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel, newCell);
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
|
||||
test('should not replace entire text model for content change with multiline content', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
let notebookEditorModel = await createTextEditorModel(this);
|
||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||
|
||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||
|
||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '"test"' + os.EOL + 'test""');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(9)).equal(' "\\"test\\"\\n",');
|
||||
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(8)).equal(' "source": [');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(10)).equal(' "test\\"\\""');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(11)).equal(' ],');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(13)).equal(' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(15)).equal(' "outputs": [],');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(16)).equal(' "execution_count": 0');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(17)).equal(' }');
|
||||
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
|
||||
test('should not replace entire text model for content change with multiline content different escaped characters', async function (): Promise<void> {
|
||||
await createNewNotebookModel();
|
||||
let notebookEditorModel = await createTextEditorModel(this);
|
||||
notebookEditorModel.replaceEntireTextEditorModel(notebookModel, undefined);
|
||||
|
||||
let newCell = notebookModel.addCell(CellTypes.Code);
|
||||
setupTextEditorModelWithEmptyOutputs(notebookEditorModel, newCell);
|
||||
|
||||
addTextToBeginningOfTextEditorModel(notebookEditorModel, newCell, '"""""test"' + os.EOL + '"""""""test\\""');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(9)).equal(' "\\"\\"\\"\\"\\"test\\"\\n",');
|
||||
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(8)).equal(' "source": [');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(10)).equal(' "\\"\\"\\"\\"\\"\\"\\"test\\\\\\"\\""');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(11)).equal(' ],');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(13)).equal(' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(15)).equal(' "outputs": [],');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(16)).equal(' "execution_count": 0');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(17)).equal(' }');
|
||||
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(false);
|
||||
});
|
||||
|
||||
async function createNewNotebookModel() {
|
||||
let options: INotebookModelOptions = Object.assign({}, defaultModelOptions, <Partial<INotebookModelOptions>><unknown>{
|
||||
factory: mockModelFactory.object
|
||||
@@ -645,4 +869,47 @@ suite('Notebook Editor Model', function (): void {
|
||||
await textFileEditorModel.load();
|
||||
return new NotebookEditorModel(defaultUri, textFileEditorModel, mockNotebookService.object, accessor.textFileService, testResourcePropertiesService);
|
||||
}
|
||||
|
||||
function setupTextEditorModelWithEmptyOutputs(notebookEditorModel: NotebookEditorModel, newCell: ICellModel) {
|
||||
// clear outputs
|
||||
newCell[<any>'_outputs'] = [];
|
||||
|
||||
let contentChange: NotebookContentChange = {
|
||||
changeType: NotebookChangeType.CellsModified,
|
||||
cells: [newCell],
|
||||
cellIndex: 0
|
||||
};
|
||||
|
||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellsModified);
|
||||
should(notebookEditorModel.lastEditFullReplacement).equal(true);
|
||||
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(14)).equal(' "outputs": [],');
|
||||
}
|
||||
|
||||
function addTextToBeginningOfTextEditorModel(notebookEditorModel: NotebookEditorModel, newCell: ICellModel, textToAdd: string) {
|
||||
let contentChange: NotebookContentChange = {
|
||||
changeType: NotebookChangeType.CellSourceUpdated,
|
||||
cells: [newCell],
|
||||
cellIndex: 0,
|
||||
modelContentChangedEvent: {
|
||||
changes: [{ range: new Range(1, 1, 1, 1), rangeLength: 0, rangeOffset: 0, text: textToAdd }],
|
||||
eol: '\n',
|
||||
isFlush: false,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
versionId: 2
|
||||
}
|
||||
};
|
||||
|
||||
notebookEditorModel.updateModel(contentChange, NotebookChangeType.CellSourceUpdated);
|
||||
}
|
||||
|
||||
function ensureStaticContentInOneLineCellIsCorrect(notebookEditorModel: NotebookEditorModel, newCell: ICellModel) {
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(8)).equal(' "source": [');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(10)).equal(' ],');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(12)).equal(' "azdata_cell_guid": "' + newCell.cellGuid + '"');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(14)).equal(' "outputs": [],');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(15)).equal(' "execution_count": 0');
|
||||
should(notebookEditorModel.editorModel.textEditorModel.getLineContent(16)).equal(' }');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -302,8 +302,12 @@ export class QueryInput extends EditorInput implements IEncodingSupport, IConnec
|
||||
}
|
||||
|
||||
public onConnectCanceled(): void {
|
||||
// If we're currently connecting and then cancel, set connected state to false
|
||||
// Otherwise, keep connected state as it was
|
||||
if (this.state.connecting) {
|
||||
this.state.connected = false;
|
||||
}
|
||||
this.state.connecting = false;
|
||||
this.state.connected = false;
|
||||
}
|
||||
|
||||
public onConnectSuccess(params?: INewConnectionParams): void {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="#C5C5C5"/>
|
||||
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="#C5C5C5"/>
|
||||
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="#C5C5C5"/>
|
||||
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="#C5C5C5"/>
|
||||
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="#C5C5C5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 484 B |
@@ -0,0 +1,7 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="white"/>
|
||||
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="white"/>
|
||||
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="white"/>
|
||||
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="white"/>
|
||||
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 474 B |
@@ -0,0 +1,7 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 12.6L10.7 13.3L12.3 11.7L13.9 13.3L14.7 12.6L13 11L14.7 9.40005L13.9 8.60005L12.3 10.3L10.7 8.60005L10 9.40005L11.6 11L10 12.6Z" fill="#424242"/>
|
||||
<path d="M1 4L15 4L15 3L1 3L1 4Z" fill="#424242"/>
|
||||
<path d="M1 7L15 7L15 6L1 6L1 7Z" fill="#424242"/>
|
||||
<path d="M9 9.5L9 9L1 9L1 10L9 10L9 9.5Z" fill="#424242"/>
|
||||
<path d="M9 13L9 12.5L9 12L1 12L1 13L9 13Z" fill="#424242"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 484 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#f6f6f6;}.icon-canvas-transparent{opacity:0;}.icon-vs-action-blue{fill:#00539c;}</style></defs><title>pause</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13,2V14H8.5V2ZM3,14H7.5V2H3Z"/></g><g id="iconBg"><path class="icon-vs-action-blue" d="M4,3H6.5V13H4ZM9.5,3V13H12V3Z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 505 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.icon-canvas-transparent,.icon-vs-out{fill:#252526;}.icon-canvas-transparent{opacity:0;}.icon-vs-action-blue{fill:#75beff;}</style></defs><title>pause</title><g id="canvas"><path class="icon-canvas-transparent" d="M16,0V16H0V0Z"/></g><g id="outline" style="display: none;"><path class="icon-vs-out" d="M13,2V14H8.5V2ZM3,14H7.5V2H3Z"/></g><g id="iconBg"><path class="icon-vs-action-blue" d="M4,3H6.5V13H4ZM9.5,3V13H12V3Z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 505 B |