mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-19 02:51:37 -05:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6aac0b6056 | ||
|
|
8e234d9b2d | ||
|
|
70819252a9 | ||
|
|
ba264d8311 | ||
|
|
5de002e5c1 | ||
|
|
0b771abad2 | ||
|
|
00041c8ecd | ||
|
|
0225d6d9f9 | ||
|
|
fb4260d71c | ||
|
|
fa253158f4 |
@@ -77,7 +77,8 @@ const vsce = require('vsce');
|
||||
const sqlBuiltInExtensions = [
|
||||
// Add SQL built-in extensions here.
|
||||
// the extension will be excluded from SQLOps package and will have separate vsix packages
|
||||
'agent'
|
||||
'agent',
|
||||
'profiler'
|
||||
];
|
||||
|
||||
const vscodeEntryPoints = _.flatten([
|
||||
|
||||
@@ -35,7 +35,8 @@ const extensions = [
|
||||
'merge-conflict',
|
||||
'insights-default',
|
||||
'account-provider-azure',
|
||||
'agent'
|
||||
'agent',
|
||||
'profiler'
|
||||
];
|
||||
|
||||
extensions.forEach(extension => yarnInstall(`extensions/${extension}`));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
||||
"version": "1.4.0-alpha.31",
|
||||
"version": "1.4.0-alpha.35",
|
||||
"downloadFileNames": {
|
||||
"Windows_86": "win-x86-netcoreapp2.1.zip",
|
||||
"Windows_64": "win-x64-netcoreapp2.1.zip",
|
||||
|
||||
@@ -49,9 +49,9 @@ core-util-is@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.1.5":
|
||||
version "0.1.5"
|
||||
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/21b0bacfc759689a6c280408528c6029a21b1abf"
|
||||
"dataprotocol-client@github:Microsoft/sqlops-dataprotocolclient#0.1.7":
|
||||
version "0.1.7"
|
||||
resolved "https://codeload.github.com/Microsoft/sqlops-dataprotocolclient/tar.gz/d50285b03d0d5073c086362c5c96afb279320607"
|
||||
dependencies:
|
||||
vscode-languageclient "3.5.0"
|
||||
|
||||
|
||||
2
extensions/profiler/.vscodeignore
Normal file
2
extensions/profiler/.vscodeignore
Normal file
@@ -0,0 +1,2 @@
|
||||
client/src/**
|
||||
client/tsconfig.json
|
||||
25
extensions/profiler/README.md
Normal file
25
extensions/profiler/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# SQL Server Profiler for SQL Operations Studio
|
||||
|
||||
Welcome to the SQL Server Profiler for SQL Operations Studio! The SQL Server Profiler extension provides a simple SQL Server tracing solution similar to SSMS Profiler except built using XEvents. SSMS Profiler is very easy to use and has good default values for the most common tracing configurations. The UX is optimized for browsing through events and viewing the associated T-SQL text. The SQL Server Profiler for SQL Operations Studio also assumes good default values for collecting T-SQL execution activities with an easy to use UX.
|
||||
|
||||
Common SQL Profiler use-cases taken from https://docs.microsoft.com/en-us/sql/tools/sql-server-profiler/sql-server-profiler.
|
||||
|
||||
- Stepping through problem queries to find the cause of the problem.
|
||||
- Finding and diagnosing slow-running queries.
|
||||
- Capturing the series of Transact-SQL statements that lead to a problem.
|
||||
- Monitoring the performance of SQL Server to tune workloads.
|
||||
- Correlating performance counters to diagnose problems.
|
||||
|
||||
## 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/sqlopsstudio/master/LICENSE.txt).
|
||||
63
extensions/profiler/client/src/apiWrapper.ts
Normal file
63
extensions/profiler/client/src/apiWrapper.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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';
|
||||
import * as data from 'sqlops';
|
||||
|
||||
/**
|
||||
* Wrapper class to act as a facade over VSCode and Data APIs and allow us to test / mock callbacks into
|
||||
* this API from our code
|
||||
*
|
||||
* @export
|
||||
* @class ApiWrapper
|
||||
*/
|
||||
export class ApiWrapper {
|
||||
// Data APIs
|
||||
|
||||
public registerWebviewProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
|
||||
return data.dashboard.registerWebviewProvider(widgetId, handler);
|
||||
}
|
||||
|
||||
|
||||
public registerControlHostProvider(widgetId: string, handler: (webview: data.DashboardWebview) => void): void {
|
||||
return data.dashboard.registerWebviewProvider(widgetId, handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configuration for a extensionName
|
||||
* @param extensionName The string name of the extension to get the configuration for
|
||||
* @param resource The optional URI, as a URI object or a string, to use to get resource-scoped configurations
|
||||
*/
|
||||
public getConfiguration(extensionName: string, resource?: vscode.Uri | string): vscode.WorkspaceConfiguration {
|
||||
if (typeof resource === 'string') {
|
||||
try {
|
||||
resource = this.parseUri(resource);
|
||||
} catch (e) {
|
||||
resource = undefined;
|
||||
}
|
||||
}
|
||||
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse uri
|
||||
*/
|
||||
public parseUri(uri: string): vscode.Uri {
|
||||
return vscode.Uri.parse(uri);
|
||||
}
|
||||
|
||||
public showOpenDialog(options: vscode.OpenDialogOptions): Thenable<vscode.Uri[] | undefined> {
|
||||
return vscode.window.showOpenDialog(options);
|
||||
}
|
||||
|
||||
public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
|
||||
return vscode.window.showErrorMessage(message, ...items);
|
||||
}
|
||||
|
||||
public get workspaceRootPath(): string {
|
||||
return vscode.workspace.rootPath;
|
||||
}
|
||||
}
|
||||
23
extensions/profiler/client/src/main.ts
Normal file
23
extensions/profiler/client/src/main.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 vscode = require('vscode');
|
||||
import { MainController } from './mainController';
|
||||
import { ApiWrapper } from './apiWrapper';
|
||||
export let controller: MainController;
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
let apiWrapper = new ApiWrapper();
|
||||
controller = new MainController(context, apiWrapper);
|
||||
controller.activate();
|
||||
}
|
||||
|
||||
// this method is called when your extension is deactivated
|
||||
export function deactivate(): void {
|
||||
if (controller) {
|
||||
controller.deactivate();
|
||||
}
|
||||
}
|
||||
32
extensions/profiler/client/src/mainController.ts
Normal file
32
extensions/profiler/client/src/mainController.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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';
|
||||
import * as data from 'sqlops';
|
||||
import { ApiWrapper } from './apiWrapper';
|
||||
|
||||
/**
|
||||
* The main controller class that initializes the extension
|
||||
*/
|
||||
export class MainController {
|
||||
protected _apiWrapper: ApiWrapper;
|
||||
protected _context: vscode.ExtensionContext;
|
||||
|
||||
// PUBLIC METHODS //////////////////////////////////////////////////////
|
||||
public constructor(context: vscode.ExtensionContext, apiWrapper?: ApiWrapper) {
|
||||
this._apiWrapper = apiWrapper || new ApiWrapper();
|
||||
this._context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates the extension
|
||||
*/
|
||||
public deactivate(): void {
|
||||
}
|
||||
|
||||
public activate(): void {
|
||||
}
|
||||
}
|
||||
8
extensions/profiler/client/src/typings/ref.d.ts
vendored
Normal file
8
extensions/profiler/client/src/typings/ref.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/// <reference path='../../../../../src/vs/vscode.d.ts'/>
|
||||
/// <reference path='../../../../../src/sql/sqlops.d.ts'/>
|
||||
/// <reference types='@types/node'/>
|
||||
19
extensions/profiler/client/tsconfig.json
Normal file
19
extensions/profiler/client/tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"outDir": "./out",
|
||||
"lib": [
|
||||
"es6", "es2015.promise"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"declaration": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
BIN
extensions/profiler/images/sqlserver.png
Normal file
BIN
extensions/profiler/images/sqlserver.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
44
extensions/profiler/package.json
Normal file
44
extensions/profiler/package.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "profiler",
|
||||
"displayName": "SQL Server Profiler",
|
||||
"description": "SQL Server Profiler for SQL Operations Studio",
|
||||
"version": "0.30.0",
|
||||
"publisher": "Microsoft",
|
||||
"preview": true,
|
||||
"license": "https://raw.githubusercontent.com/Microsoft/sqlopsstudio/master/LICENSE.txt",
|
||||
"icon": "images/sqlserver.png",
|
||||
"aiKey": "AIF-5574968e-856d-40d2-af67-c89a14e76412",
|
||||
"engines": {
|
||||
"vscode": "0.10.x"
|
||||
},
|
||||
"activationEvents": [
|
||||
"*"
|
||||
],
|
||||
"main": "./client/out/main",
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:profiler-client"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/sqlopsstudio.git"
|
||||
},
|
||||
"extensionDependencies": [
|
||||
"Microsoft.mssql"
|
||||
],
|
||||
"contributes": {
|
||||
|
||||
"commands": [
|
||||
{
|
||||
"command": "profiler.newProfiler",
|
||||
"title": "New Profiler",
|
||||
"category": "Profiler"
|
||||
}
|
||||
],
|
||||
"outputChannels": [
|
||||
"sqlprofiler"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"vscode": "1.0.1"
|
||||
}
|
||||
}
|
||||
2085
extensions/profiler/yarn.lock
Normal file
2085
extensions/profiler/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sqlops",
|
||||
"version": "0.30.1",
|
||||
"version": "0.30.2",
|
||||
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
@@ -59,7 +59,7 @@
|
||||
"reflect-metadata": "^0.1.8",
|
||||
"rxjs": "5.4.0",
|
||||
"semver": "4.3.6",
|
||||
"slickgrid": "github:anthonydresser/SlickGrid#2.3.16",
|
||||
"slickgrid": "github:anthonydresser/SlickGrid#2.3.17",
|
||||
"spdlog": "0.6.0",
|
||||
"svg.js": "^2.2.5",
|
||||
"sudo-prompt": "^8.0.0",
|
||||
|
||||
489
samples/sqlservices/package-lock.json
generated
489
samples/sqlservices/package-lock.json
generated
@@ -27,6 +27,12 @@
|
||||
"through2": "2.0.3"
|
||||
}
|
||||
},
|
||||
"@types/handlebars": {
|
||||
"version": "4.0.37",
|
||||
"resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.37.tgz",
|
||||
"integrity": "sha512-c/g99PQsJEFYdK3LT1qgPAZ61fu/oFOaEhov/6ZuUNMi1xQFbAOSThlX8fAQLf+QoGXtyv4S39OjIRXf3HkBtw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "7.0.58",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.58.tgz",
|
||||
@@ -51,11 +57,30 @@
|
||||
"json-schema-traverse": "0.3.1"
|
||||
}
|
||||
},
|
||||
"align-text": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
|
||||
"integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
|
||||
"requires": {
|
||||
"kind-of": "3.2.2",
|
||||
"longest": "1.0.1",
|
||||
"repeat-string": "1.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"kind-of": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||
"requires": {
|
||||
"is-buffer": "1.1.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"amdefine": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
|
||||
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
|
||||
},
|
||||
"ansi-colors": {
|
||||
"version": "1.1.0",
|
||||
@@ -136,6 +161,15 @@
|
||||
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
|
||||
"dev": true
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sprintf-js": "1.0.3"
|
||||
}
|
||||
},
|
||||
"arr-diff": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
|
||||
@@ -289,6 +323,11 @@
|
||||
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
|
||||
"dev": true
|
||||
},
|
||||
"async": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
|
||||
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
|
||||
},
|
||||
"async-done": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/async-done/-/async-done-1.2.4.tgz",
|
||||
@@ -420,6 +459,12 @@
|
||||
"inherits": "2.0.3"
|
||||
}
|
||||
},
|
||||
"boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
|
||||
"dev": true
|
||||
},
|
||||
"boom": {
|
||||
"version": "2.10.1",
|
||||
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
|
||||
@@ -538,6 +583,16 @@
|
||||
"integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=",
|
||||
"dev": true
|
||||
},
|
||||
"center-align": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
|
||||
"integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"align-text": "0.1.4",
|
||||
"lazy-cache": "1.0.4"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
@@ -551,6 +606,20 @@
|
||||
"supports-color": "2.0.0"
|
||||
}
|
||||
},
|
||||
"cheerio": {
|
||||
"version": "1.0.0-rc.2",
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz",
|
||||
"integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"css-select": "1.2.0",
|
||||
"dom-serializer": "0.1.0",
|
||||
"entities": "1.1.1",
|
||||
"htmlparser2": "3.9.2",
|
||||
"lodash": "4.17.10",
|
||||
"parse5": "3.0.3"
|
||||
}
|
||||
},
|
||||
"child-process-promise": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/child-process-promise/-/child-process-promise-2.2.1.tgz",
|
||||
@@ -888,6 +957,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"css-select": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
||||
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"boolbase": "1.0.0",
|
||||
"css-what": "2.1.0",
|
||||
"domutils": "1.5.1",
|
||||
"nth-check": "1.0.1"
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz",
|
||||
"integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=",
|
||||
"dev": true
|
||||
},
|
||||
"d": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
|
||||
@@ -954,8 +1041,7 @@
|
||||
"decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
|
||||
"dev": true
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||
},
|
||||
"decode-uri-component": {
|
||||
"version": "0.2.0",
|
||||
@@ -1043,6 +1129,12 @@
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||
"dev": true
|
||||
},
|
||||
"denodeify": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz",
|
||||
"integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=",
|
||||
"dev": true
|
||||
},
|
||||
"detect-file": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
|
||||
@@ -1061,6 +1153,49 @@
|
||||
"integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==",
|
||||
"dev": true
|
||||
},
|
||||
"dom-serializer": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
|
||||
"integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "1.1.3",
|
||||
"entities": "1.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"domelementtype": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
|
||||
"integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"domelementtype": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
|
||||
"integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=",
|
||||
"dev": true
|
||||
},
|
||||
"domhandler": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
|
||||
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "1.3.0"
|
||||
}
|
||||
},
|
||||
"domutils": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
|
||||
"integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"dom-serializer": "0.1.0",
|
||||
"domelementtype": "1.3.0"
|
||||
}
|
||||
},
|
||||
"duplexer": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
||||
@@ -1143,6 +1278,12 @@
|
||||
"once": "1.4.0"
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
|
||||
"integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=",
|
||||
"dev": true
|
||||
},
|
||||
"error-ex": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
|
||||
@@ -1630,6 +1771,16 @@
|
||||
"integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=",
|
||||
"dev": true
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
|
||||
"integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11",
|
||||
"jsonfile": "4.0.0",
|
||||
"universalify": "0.1.1"
|
||||
}
|
||||
},
|
||||
"fs-mkdirp-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
|
||||
@@ -2762,8 +2913,7 @@
|
||||
"graceful-fs": {
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
|
||||
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
|
||||
},
|
||||
"growl": {
|
||||
"version": "1.10.3",
|
||||
@@ -3928,6 +4078,27 @@
|
||||
"glogg": "1.0.1"
|
||||
}
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.0.11",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz",
|
||||
"integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=",
|
||||
"requires": {
|
||||
"async": "1.5.2",
|
||||
"optimist": "0.6.1",
|
||||
"source-map": "0.4.4",
|
||||
"uglify-js": "2.8.29"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
|
||||
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
|
||||
"requires": {
|
||||
"amdefine": "1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
@@ -4047,6 +4218,20 @@
|
||||
"integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==",
|
||||
"dev": true
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "3.9.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
|
||||
"integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "1.3.0",
|
||||
"domhandler": "2.4.2",
|
||||
"domutils": "1.5.1",
|
||||
"entities": "1.1.1",
|
||||
"inherits": "2.0.3",
|
||||
"readable-stream": "2.3.5"
|
||||
}
|
||||
},
|
||||
"http-signature": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
|
||||
@@ -4135,8 +4320,7 @@
|
||||
"is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
},
|
||||
"is-builtin-module": {
|
||||
"version": "1.0.0",
|
||||
@@ -4443,6 +4627,14 @@
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
|
||||
"dev": true
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||
"requires": {
|
||||
"graceful-fs": "4.1.11"
|
||||
}
|
||||
},
|
||||
"jsonify": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
|
||||
@@ -4497,6 +4689,12 @@
|
||||
"es6-weak-map": "2.0.2"
|
||||
}
|
||||
},
|
||||
"lazy-cache": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
|
||||
"integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
|
||||
"optional": true
|
||||
},
|
||||
"lazystream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
|
||||
@@ -4540,6 +4738,15 @@
|
||||
"resolve": "1.6.0"
|
||||
}
|
||||
},
|
||||
"linkify-it": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.0.3.tgz",
|
||||
"integrity": "sha1-2UpGSPmxwXnWT6lykSaL22zpQ08=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"uc.micro": "1.0.5"
|
||||
}
|
||||
},
|
||||
"load-json-file": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||
@@ -4553,6 +4760,12 @@
|
||||
"strip-bom": "2.0.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.10",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
|
||||
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash._basecopy": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
|
||||
@@ -4678,6 +4891,11 @@
|
||||
"lodash.escape": "3.2.0"
|
||||
}
|
||||
},
|
||||
"longest": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
|
||||
"integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc="
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz",
|
||||
@@ -4738,6 +4956,19 @@
|
||||
"object-visit": "1.0.1"
|
||||
}
|
||||
},
|
||||
"markdown-it": {
|
||||
"version": "8.4.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.1.tgz",
|
||||
"integrity": "sha512-CzzqSSNkFRUf9vlWvhK1awpJreMRqdCrBvZ8DIoDWTOkESMIF741UPAhuAmbyWmdiFPA6WARNhnu2M6Nrhwa+A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "1.0.10",
|
||||
"entities": "1.1.1",
|
||||
"linkify-it": "2.0.3",
|
||||
"mdurl": "1.0.1",
|
||||
"uc.micro": "1.0.5"
|
||||
}
|
||||
},
|
||||
"matchdep": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
|
||||
@@ -4750,6 +4981,12 @@
|
||||
"stack-trace": "0.0.10"
|
||||
}
|
||||
},
|
||||
"mdurl": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
|
||||
"dev": true
|
||||
},
|
||||
"memoizee": {
|
||||
"version": "0.4.12",
|
||||
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.12.tgz",
|
||||
@@ -4796,6 +5033,12 @@
|
||||
"to-regex": "3.0.2"
|
||||
}
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.33.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
|
||||
@@ -4941,6 +5184,12 @@
|
||||
"integrity": "sha1-WzLqB+tDyd7WEwQ0z5JvRrKn/U0=",
|
||||
"dev": true
|
||||
},
|
||||
"mute-stream": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
|
||||
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
|
||||
"dev": true
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
|
||||
@@ -5019,6 +5268,15 @@
|
||||
"once": "1.4.0"
|
||||
}
|
||||
},
|
||||
"nth-check": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz",
|
||||
"integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"boolbase": "1.0.0"
|
||||
}
|
||||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||
@@ -5207,7 +5465,6 @@
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.10",
|
||||
"wordwrap": "0.0.3"
|
||||
@@ -5216,8 +5473,7 @@
|
||||
"minimist": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5230,6 +5486,12 @@
|
||||
"readable-stream": "2.3.5"
|
||||
}
|
||||
},
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
|
||||
"dev": true
|
||||
},
|
||||
"os-locale": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
|
||||
@@ -5239,6 +5501,22 @@
|
||||
"lcid": "1.0.0"
|
||||
}
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
|
||||
"dev": true
|
||||
},
|
||||
"osenv": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
|
||||
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"os-homedir": "1.0.2",
|
||||
"os-tmpdir": "1.0.2"
|
||||
}
|
||||
},
|
||||
"p-map": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz",
|
||||
@@ -5300,6 +5578,24 @@
|
||||
"integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
|
||||
"dev": true
|
||||
},
|
||||
"parse-semver": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz",
|
||||
"integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"semver": "5.5.0"
|
||||
}
|
||||
},
|
||||
"parse5": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
|
||||
"integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "7.0.58"
|
||||
}
|
||||
},
|
||||
"pascalcase": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
|
||||
@@ -5564,6 +5860,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"read": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
|
||||
"integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mute-stream": "0.0.7"
|
||||
}
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
|
||||
@@ -5684,8 +5989,7 @@
|
||||
"repeat-string": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
|
||||
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
|
||||
"dev": true
|
||||
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
|
||||
},
|
||||
"replace-ext": {
|
||||
"version": "1.0.0",
|
||||
@@ -5915,6 +6219,15 @@
|
||||
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
|
||||
"dev": true
|
||||
},
|
||||
"right-align": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
|
||||
"integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"align-text": "0.1.4"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
|
||||
@@ -6136,8 +6449,7 @@
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
|
||||
"dev": true
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
|
||||
},
|
||||
"source-map-resolve": {
|
||||
"version": "0.5.1",
|
||||
@@ -6536,6 +6848,15 @@
|
||||
"next-tick": "1.0.0"
|
||||
}
|
||||
},
|
||||
"tmp": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz",
|
||||
"integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"os-tmpdir": "1.0.2"
|
||||
}
|
||||
},
|
||||
"to-absolute-glob": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
|
||||
@@ -6653,6 +6974,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"tunnel": {
|
||||
"version": "0.0.4",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz",
|
||||
"integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM=",
|
||||
"dev": true
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
|
||||
@@ -6666,6 +6993,16 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"typed-rest-client": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-0.12.0.tgz",
|
||||
"integrity": "sha1-Y3b1Un9CfaEh3K/f1+QeEyHgcgw=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tunnel": "0.0.4",
|
||||
"underscore": "1.8.3"
|
||||
}
|
||||
},
|
||||
"typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
@@ -6678,12 +7015,78 @@
|
||||
"integrity": "sha512-Ao/f6d/4EPLq0YwzsQz8iXflezpTkQzqAyenTiw4kCUGr1uPiFLC3+fZ+gMZz6eeI/qdRUqvC+HxIJzUAzEFdg==",
|
||||
"dev": true
|
||||
},
|
||||
"uc.micro": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz",
|
||||
"integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg==",
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "2.8.29",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
|
||||
"integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"source-map": "0.5.7",
|
||||
"uglify-to-browserify": "1.0.2",
|
||||
"yargs": "3.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"camelcase": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
|
||||
"integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
|
||||
"optional": true
|
||||
},
|
||||
"cliui": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
|
||||
"integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"center-align": "0.1.3",
|
||||
"right-align": "0.1.3",
|
||||
"wordwrap": "0.0.2"
|
||||
}
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
|
||||
"integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
|
||||
"optional": true
|
||||
},
|
||||
"yargs": {
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
|
||||
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"camelcase": "1.2.1",
|
||||
"cliui": "2.1.0",
|
||||
"decamelize": "1.2.0",
|
||||
"window-size": "0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"uglify-to-browserify": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
|
||||
"integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
|
||||
"optional": true
|
||||
},
|
||||
"unc-path-regex": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
|
||||
"integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
|
||||
"dev": true
|
||||
},
|
||||
"underscore": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
|
||||
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
|
||||
"dev": true
|
||||
},
|
||||
"underscore.string": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.4.tgz",
|
||||
@@ -6762,6 +7165,11 @@
|
||||
"through2-filter": "2.0.0"
|
||||
}
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
|
||||
"integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc="
|
||||
},
|
||||
"unset-value": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
|
||||
@@ -6814,6 +7222,12 @@
|
||||
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
|
||||
"dev": true
|
||||
},
|
||||
"url-join": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz",
|
||||
"integrity": "sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg=",
|
||||
"dev": true
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.3.0.tgz",
|
||||
@@ -6983,6 +7397,31 @@
|
||||
"vinyl": "2.1.0"
|
||||
}
|
||||
},
|
||||
"vsce": {
|
||||
"version": "1.36.2",
|
||||
"resolved": "https://registry.npmjs.org/vsce/-/vsce-1.36.2.tgz",
|
||||
"integrity": "sha512-LiQjHdoaXOHKdk/PRN5OWWeEm/4w7tnFLf8EM+pzvlz/8uk7uJiqtMjVYAYawnU7c8KbMSz9nE9M6nCTV4ZSQA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cheerio": "1.0.0-rc.2",
|
||||
"commander": "2.15.1",
|
||||
"denodeify": "1.2.1",
|
||||
"glob": "7.1.2",
|
||||
"lodash": "4.17.10",
|
||||
"markdown-it": "8.4.1",
|
||||
"mime": "1.6.0",
|
||||
"minimatch": "3.0.4",
|
||||
"osenv": "0.1.5",
|
||||
"parse-semver": "1.1.1",
|
||||
"read": "1.0.7",
|
||||
"semver": "5.5.0",
|
||||
"tmp": "0.0.29",
|
||||
"url-join": "1.1.0",
|
||||
"vso-node-api": "6.5.0",
|
||||
"yauzl": "2.9.1",
|
||||
"yazl": "2.4.3"
|
||||
}
|
||||
},
|
||||
"vscode": {
|
||||
"version": "1.1.14",
|
||||
"resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.14.tgz",
|
||||
@@ -7010,6 +7449,17 @@
|
||||
"resolved": "https://registry.npmjs.org/vscode-nls/-/vscode-nls-3.2.2.tgz",
|
||||
"integrity": "sha512-/Ur1+tgazwd51+ncRyoy0UIu4dvMdVXS9XMUULQlZIBoNGEwOhwEx9x+hHWoUjldMrOQ32t2CGKo0u6D4R6/hg=="
|
||||
},
|
||||
"vso-node-api": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/vso-node-api/-/vso-node-api-6.5.0.tgz",
|
||||
"integrity": "sha512-hFjPLMJkq02zF8U+LhZ4airH0ivaiKzGdlNAQlYFB3lWuGH/UANUrl63DVPUQOyGw+7ZNQ+ufM44T6mWN92xyg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tunnel": "0.0.4",
|
||||
"typed-rest-client": "0.12.0",
|
||||
"underscore": "1.8.3"
|
||||
}
|
||||
},
|
||||
"which": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
|
||||
@@ -7025,11 +7475,16 @@
|
||||
"integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
|
||||
"dev": true
|
||||
},
|
||||
"window-size": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
|
||||
"integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
|
||||
"optional": true
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
||||
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
|
||||
"dev": true
|
||||
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "2.1.0",
|
||||
|
||||
@@ -16,11 +16,16 @@
|
||||
],
|
||||
"main": "./out/src/extension",
|
||||
"contributes": {
|
||||
|
||||
"commands": [{
|
||||
"command": "mssql.openDialog",
|
||||
"title": "mssql.openDialog"
|
||||
}],
|
||||
"commands": [
|
||||
{
|
||||
"command": "sqlservices.openDialog",
|
||||
"title": "sqlservices.openDialog"
|
||||
},
|
||||
{
|
||||
"command": "sqlservices.openEditor",
|
||||
"title": "sqlservices.openEditor"
|
||||
}
|
||||
],
|
||||
"dashboard.tabs": [
|
||||
{
|
||||
"id": "sqlservices.tab",
|
||||
@@ -84,6 +89,7 @@
|
||||
"tslint": "^3.14.0",
|
||||
"typescript": "^2.6.1",
|
||||
"vscode": "^1.1.14",
|
||||
"@types/handlebars": "^4.0.11"
|
||||
"@types/handlebars": "^4.0.11",
|
||||
"vsce": "1.36.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,10 +40,14 @@ export default class MainController implements vscode.Disposable {
|
||||
vscode.window.showInformationMessage(`Clicked from profile ${profile.serverName}.${profile.databaseName}`);
|
||||
});
|
||||
|
||||
vscode.commands.registerCommand('mssql.openDialog', () => {
|
||||
vscode.commands.registerCommand('sqlservices.openDialog', () => {
|
||||
this.openDialog();
|
||||
});
|
||||
|
||||
vscode.commands.registerCommand('sqlservices.openEditor', () => {
|
||||
this.openEditor();
|
||||
});
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
@@ -72,9 +76,6 @@ export default class MainController implements vscode.Disposable {
|
||||
let inputBox2 = view.modelBuilder.inputBox()
|
||||
.component();
|
||||
|
||||
let inputBox3 = view.modelBuilder.inputBox()
|
||||
.component();
|
||||
|
||||
let checkbox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: 'Copy-only backup'
|
||||
@@ -114,6 +115,31 @@ export default class MainController implements vscode.Disposable {
|
||||
vscode.window.showInformationMessage(inputBox2.value);
|
||||
inputBox.value = dropdown.value;
|
||||
});
|
||||
let radioButton = view.modelBuilder.radioButton()
|
||||
.withProperties({
|
||||
value: 'option1',
|
||||
name: 'radioButtonOptions',
|
||||
label: 'Option 1',
|
||||
checked: true
|
||||
//width: 300
|
||||
}).component();
|
||||
let radioButton2 = view.modelBuilder.radioButton()
|
||||
.withProperties({
|
||||
value: 'option2',
|
||||
name: 'radioButtonOptions',
|
||||
label: 'Option 2'
|
||||
|
||||
//width: 300
|
||||
}).component();
|
||||
let flexRadioButtonsModel = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'column',
|
||||
alignItems: 'left',
|
||||
justifyContent: 'space-evenly',
|
||||
height: 50
|
||||
}).withItems([
|
||||
radioButton, radioButton2]
|
||||
, { flex: '1 1 50%' }).component();
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: inputBox,
|
||||
@@ -131,6 +157,9 @@ export default class MainController implements vscode.Disposable {
|
||||
component: inputBox2,
|
||||
title: 'Backup files',
|
||||
actions: [button, button3]
|
||||
}, {
|
||||
component: flexRadioButtonsModel,
|
||||
title: 'Options'
|
||||
}], {
|
||||
horizontal:false,
|
||||
width: 500,
|
||||
@@ -142,6 +171,22 @@ export default class MainController implements vscode.Disposable {
|
||||
sqlops.window.modelviewdialog.openDialog(dialog);
|
||||
}
|
||||
|
||||
private openEditor(): void {
|
||||
let editor = sqlops.workspace.createModelViewEditor('Test Editor view');
|
||||
editor.registerContent(async view => {
|
||||
let inputBox = view.modelBuilder.inputBox()
|
||||
.withValidation(component => component.value !== 'valid')
|
||||
.component();
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: inputBox,
|
||||
title: 'Enter anything but "valid"'
|
||||
}]).component();
|
||||
await view.initializeModel(formModel);
|
||||
});
|
||||
editor.openEditor();
|
||||
}
|
||||
|
||||
private registerSqlServicesModelView(): void {
|
||||
sqlops.ui.registerModelViewProvider('sqlservices', async (view) => {
|
||||
let flexModel = view.modelBuilder.flexContainer()
|
||||
|
||||
@@ -50,8 +50,8 @@ let idPool = 0;
|
||||
<div *ngIf="!options.showTabsWhenOne ? _tabs.length !== 1 : true" class="composite title">
|
||||
<div class="tabContainer">
|
||||
<div class="tabList" role="tablist" scrollable [horizontalScroll]="ScrollbarVisibility.Auto" [verticalScroll]="ScrollbarVisibility.Hidden" [scrollYToX]="true">
|
||||
<div *ngFor="let tab of _tabs">
|
||||
<tab-header [active]="_activeTab === tab" [tab]="tab" [showIcon]="options.showIcon" (onSelectTab)='selectTab($event)' (onCloseTab)='closeTab($event)'> </tab-header>
|
||||
<div role="presentation" *ngFor="let tab of _tabs">
|
||||
<tab-header role="presentation" [active]="_activeTab === tab" [tab]="tab" [showIcon]="options.showIcon" (onSelectTab)='selectTab($event)' (onCloseTab)='closeTab($event)'></tab-header>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -66,6 +66,8 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
this.$header.append(actionbarcontainer);
|
||||
this.$parent.append(this.$header);
|
||||
this.$body = $('tabBody');
|
||||
this.$body.attr('role', 'tabpanel');
|
||||
this.$body.attr('tabindex', '0');
|
||||
this.$parent.append(this.$body);
|
||||
}
|
||||
|
||||
@@ -92,7 +94,7 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
tabHeaderElement.attr('tabindex', '0');
|
||||
tabHeaderElement.attr('role', 'tab');
|
||||
tabHeaderElement.attr('aria-selected', 'false');
|
||||
tabHeaderElement.attr('aria-label', tab.title);
|
||||
tabHeaderElement.attr('aria-controls', tab.identifier);
|
||||
let tabElement = $('.tab');
|
||||
tabHeaderElement.append(tabElement);
|
||||
let tabLabel = $('a.tabLabel');
|
||||
@@ -124,6 +126,7 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
this._shownTab = id;
|
||||
this.$body.clearChildren();
|
||||
let tab = this._tabMap.get(this._shownTab);
|
||||
this.$body.attr('aria-labelledby', tab.identifier);
|
||||
tab.label.addClass('active');
|
||||
tab.header.addClass('active');
|
||||
tab.header.attr('aria-selected', 'true');
|
||||
|
||||
@@ -13,7 +13,7 @@ export abstract class TabChild {
|
||||
@Component({
|
||||
selector: 'tab',
|
||||
template: `
|
||||
<div class="visibility" [class.hidden]="shouldBeHidden()" *ngIf="shouldBeIfed()" class="fullsize">
|
||||
<div role="tabpanel" [attr.aria-labelledby]="identifier" tabindex="0" class="visibility" [class.hidden]="shouldBeHidden()" *ngIf="shouldBeIfed()" class="fullsize">
|
||||
<ng-container *ngTemplateOutlet="templateRef"></ng-container>
|
||||
</div>
|
||||
`
|
||||
|
||||
@@ -19,8 +19,8 @@ import { CloseTabAction } from './tabActions';
|
||||
@Component({
|
||||
selector: 'tab-header',
|
||||
template: `
|
||||
<div #actionHeader class="tab-header" style="flex: 0 0; flex-direction: row; height: 100%" [class.active]="tab.active" tabindex="0" (keyup)="onKey($event)">
|
||||
<span class="tab" (click)="selectTab(tab)" role="tab" [attr.aria-selected]="tab.active" [attr.aria-label]="tab.title">
|
||||
<div #actionHeader role="presentation" class="tab-header" style="flex: 0 0; flex-direction: row; height: 100%" [class.active]="tab.active" tabindex="0" (keyup)="onKey($event)">
|
||||
<span class="tab" (click)="selectTab(tab)" role="tab" [attr.aria-selected]="tab.active" [attr.aria-controls]="tab.title">
|
||||
<a class="tabLabel" [class.active]="tab.active" #tabLabel>
|
||||
</a>
|
||||
</span>
|
||||
|
||||
83
src/sql/base/browser/ui/radioButton/radioButton.ts
Normal file
83
src/sql/base/browser/ui/radioButton/radioButton.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 DOM from 'vs/base/browser/dom';
|
||||
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
|
||||
export interface IRadioButtonOptions {
|
||||
label: string;
|
||||
enabled?: boolean;
|
||||
checked?: boolean;
|
||||
}
|
||||
|
||||
export class RadioButton extends Widget {
|
||||
|
||||
private inputElement: HTMLInputElement;
|
||||
private _onClicked = new Emitter<void>();
|
||||
public readonly onClicked: Event<void> = this._onClicked.event;
|
||||
private _label: HTMLSpanElement;
|
||||
|
||||
constructor(container: HTMLElement, opts: IRadioButtonOptions) {
|
||||
super();
|
||||
this.inputElement = document.createElement('input');
|
||||
this.inputElement.type = 'radio';
|
||||
|
||||
this._label = document.createElement('span');
|
||||
|
||||
this.label = opts.label;
|
||||
this.enabled = opts.enabled || true;
|
||||
this.checked = opts.checked || false;
|
||||
this.onclick(this.inputElement, () => this._onClicked.fire());
|
||||
|
||||
container.appendChild(this.inputElement);
|
||||
container.appendChild(this._label);
|
||||
}
|
||||
|
||||
public set name(value: string) {
|
||||
this.inputElement.setAttribute('name', value);
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return this.inputElement.getAttribute('name');
|
||||
}
|
||||
|
||||
public set value(value: string) {
|
||||
this.inputElement.setAttribute('value', value);
|
||||
}
|
||||
|
||||
public get value(): string {
|
||||
return this.inputElement.getAttribute('value');
|
||||
}
|
||||
|
||||
public set checked(val: boolean) {
|
||||
this.inputElement.checked = val;
|
||||
}
|
||||
|
||||
public get checked(): boolean {
|
||||
return this.inputElement.checked;
|
||||
}
|
||||
|
||||
public set enabled(val: boolean) {
|
||||
this.inputElement.disabled = !val;
|
||||
}
|
||||
|
||||
public get enabled(): boolean {
|
||||
return !this.inputElement.disabled;
|
||||
}
|
||||
|
||||
public isEnabled(): boolean {
|
||||
return !this.inputElement.hasAttribute('disabled');
|
||||
}
|
||||
|
||||
public set label(val: string) {
|
||||
this._label.innerText = val;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -78,6 +78,11 @@ export default class CheckBoxComponent extends ComponentBase implements ICompone
|
||||
super.setProperties(properties);
|
||||
this._input.checked = this.checked;
|
||||
this._input.label = this.label;
|
||||
if (this.enabled) {
|
||||
this._input.enable();
|
||||
} else {
|
||||
this._input.disable();
|
||||
}
|
||||
}
|
||||
|
||||
// CSS-bound properties
|
||||
@@ -87,11 +92,7 @@ export default class CheckBoxComponent extends ComponentBase implements ICompone
|
||||
}
|
||||
|
||||
public set value(newValue: boolean) {
|
||||
this.setPropertyFromUI<sqlops.CheckBoxProperties, boolean>(this.setInputBoxProperties, newValue);
|
||||
}
|
||||
|
||||
private setInputBoxProperties(properties: sqlops.CheckBoxProperties, value: boolean): void {
|
||||
properties.checked = value;
|
||||
this.setPropertyFromUI<sqlops.CheckBoxProperties, boolean>((properties, value) => { properties.checked = value; }, newValue);
|
||||
}
|
||||
|
||||
private get label(): string {
|
||||
@@ -99,10 +100,6 @@ export default class CheckBoxComponent extends ComponentBase implements ICompone
|
||||
}
|
||||
|
||||
private set label(newValue: string) {
|
||||
this.setPropertyFromUI<sqlops.CheckBoxProperties, string>(this.setValueProperties, newValue);
|
||||
}
|
||||
|
||||
private setValueProperties(properties: sqlops.CheckBoxProperties, label: string): void {
|
||||
properties.label = label;
|
||||
this.setPropertyFromUI<sqlops.CheckBoxProperties, string>((properties, label) => { properties.label = label; }, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,15 @@ export abstract class ComponentBase extends Disposable implements IComponent, On
|
||||
public get enabled(): boolean {
|
||||
let properties = this.getProperties();
|
||||
let enabled = properties['enabled'];
|
||||
return enabled !== undefined ? <boolean>enabled : true;
|
||||
if (enabled === undefined) {
|
||||
enabled = true;
|
||||
properties['enabled'] = enabled;
|
||||
this.fireEvent({
|
||||
eventType: ComponentEventType.PropertiesChanged,
|
||||
args: this.getProperties()
|
||||
});
|
||||
}
|
||||
return <boolean>enabled;
|
||||
}
|
||||
|
||||
public get valid(): boolean {
|
||||
|
||||
@@ -10,6 +10,7 @@ import InputBoxComponent from './inputbox.component';
|
||||
import DropDownComponent from './dropdown.component';
|
||||
import ButtonComponent from './button.component';
|
||||
import CheckBoxComponent from './checkbox.component';
|
||||
import RadioButtonComponent from './radioButton.component';
|
||||
import { registerComponentType } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
||||
import { ModelComponentTypes } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
|
||||
@@ -34,3 +35,6 @@ registerComponentType(BUTTON_COMPONENT, ModelComponentTypes.Button, ButtonCompon
|
||||
|
||||
export const CHECKBOX_COMPONENT = 'checkbox-component';
|
||||
registerComponentType(CHECKBOX_COMPONENT, ModelComponentTypes.CheckBox, CheckBoxComponent);
|
||||
|
||||
export const RADIOBUTTON_COMPONENT = 'radiobutton-component';
|
||||
registerComponentType(RADIOBUTTON_COMPONENT, ModelComponentTypes.RadioButton, RadioButtonComponent);
|
||||
|
||||
@@ -87,6 +87,7 @@ export default class DropDownComponent extends ComponentBase implements ICompone
|
||||
if (this.value) {
|
||||
this._dropdown.value = this.value;
|
||||
}
|
||||
this._dropdown.enabled = this.enabled;
|
||||
}
|
||||
|
||||
// CSS-bound properties
|
||||
|
||||
@@ -22,7 +22,7 @@ class FlexItem {
|
||||
@Component({
|
||||
template: `
|
||||
<div *ngIf="items" class="flexContainer" [style.flexFlow]="flexFlow" [style.justifyContent]="justifyContent"
|
||||
[style.alignItems]="alignItems" [style.alignContent]="alignContent">
|
||||
[style.alignItems]="alignItems" [style.alignContent]="alignContent" [style.height]="height">
|
||||
<div *ngFor="let item of items" [style.flex]="getItemFlex(item)" [style.order]="getItemOrder(item)" >
|
||||
<model-component-wrapper [descriptor]="item.descriptor" [modelStore]="modelStore">
|
||||
</model-component-wrapper>
|
||||
@@ -37,6 +37,7 @@ export default class FlexContainer extends ContainerBase<FlexItemLayout> impleme
|
||||
private _justifyContent: string;
|
||||
private _alignItems: string;
|
||||
private _alignContent: string;
|
||||
private _height: string;
|
||||
|
||||
@ViewChildren(ModelComponentWrapper) private _componentWrappers: QueryList<ModelComponentWrapper>;
|
||||
|
||||
@@ -70,6 +71,7 @@ export default class FlexContainer extends ContainerBase<FlexItemLayout> impleme
|
||||
this._justifyContent= layout.justifyContent ? layout.justifyContent : '';
|
||||
this._alignItems= layout.alignItems ? layout.alignItems : '';
|
||||
this._alignContent= layout.alignContent ? layout.alignContent : '';
|
||||
this._height= layout.height ? layout.height + 'px' : '';
|
||||
this.layout();
|
||||
}
|
||||
|
||||
@@ -86,6 +88,10 @@ export default class FlexContainer extends ContainerBase<FlexItemLayout> impleme
|
||||
return this._alignItems;
|
||||
}
|
||||
|
||||
public get height(): string {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
public get alignContent(): string {
|
||||
return this._alignContent;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
|
||||
import { ModelViewInput } from 'sql/parts/modelComponents/modelEditor/modelViewInput';
|
||||
import { ModelViewEditor } from 'sql/parts/modelComponents/modelEditor/modelViewEditor';
|
||||
|
||||
// Model View editor registration
|
||||
const viewModelEditorDescriptor = new EditorDescriptor(
|
||||
ModelViewEditor,
|
||||
ModelViewEditor.ID,
|
||||
'ViewModel'
|
||||
);
|
||||
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
|
||||
.registerEditor(viewModelEditorDescriptor, [new SyncDescriptor(ModelViewInput)]);
|
||||
71
src/sql/parts/modelComponents/modelEditor/modelViewEditor.ts
Normal file
71
src/sql/parts/modelComponents/modelEditor/modelViewEditor.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { Builder, $ } from 'vs/base/browser/builder';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { Dimension } from 'vs/workbench/services/part/common/partService';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
|
||||
import { ModelViewInput } from 'sql/parts/modelComponents/modelEditor/modelViewInput';
|
||||
import { IBootstrapService } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { Dialog } from 'sql/platform/dialog/dialogTypes';
|
||||
import { DialogPane } from 'sql/platform/dialog/dialogPane';
|
||||
|
||||
export class ModelViewEditor extends BaseEditor {
|
||||
|
||||
public static ID: string = 'workbench.editor.modelViewEditor';
|
||||
private _modelViewMap = new Map<string, HTMLElement>();
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IBootstrapService private _bootstrapService: IBootstrapService
|
||||
) {
|
||||
super(ModelViewEditor.ID, telemetryService, themeService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to create the editor in the parent builder.
|
||||
*/
|
||||
public createEditor(parent: Builder): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets focus on this editor. Specifically, it sets the focus on the hosted text editor.
|
||||
*/
|
||||
public focus(): void {
|
||||
}
|
||||
|
||||
public setInput(input: ModelViewInput, options?: EditorOptions): TPromise<void, any> {
|
||||
if (this.input && this.input.matches(input)) {
|
||||
return TPromise.as(undefined);
|
||||
}
|
||||
const parentElement = this.getContainer().getHTMLElement();
|
||||
$(parentElement).clearChildren();
|
||||
|
||||
if (!this._modelViewMap.get(input.modelViewId)) {
|
||||
let modelViewContainer = DOM.$('div.model-view-container');
|
||||
let dialogPane = new DialogPane(input.title, input.modelViewId, () => undefined, this._bootstrapService);
|
||||
dialogPane.createBody(modelViewContainer);
|
||||
this._modelViewMap.set(input.modelViewId, modelViewContainer);
|
||||
}
|
||||
let element = this._modelViewMap.get(input.modelViewId);
|
||||
DOM.append(parentElement, element);
|
||||
|
||||
return super.setInput(input, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the internal variable keeping track of the editor's size, and re-calculates the sash position.
|
||||
* To be called when the container of this editor changes size.
|
||||
*/
|
||||
public layout(dimension: Dimension): void {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
37
src/sql/parts/modelComponents/modelEditor/modelViewInput.ts
Normal file
37
src/sql/parts/modelComponents/modelEditor/modelViewInput.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IEditorModel } from 'vs/platform/editor/common/editor';
|
||||
import { EditorInput } from 'vs/workbench/common/editor';
|
||||
|
||||
export class ModelViewInput extends EditorInput {
|
||||
|
||||
public static ID: string = 'workbench.editorinputs.ModelViewEditorInput';
|
||||
|
||||
constructor(private _title: string, private _modelViewId: string) {
|
||||
super();
|
||||
}
|
||||
|
||||
public get title(): string {
|
||||
return this._title;
|
||||
}
|
||||
|
||||
public get modelViewId(): string {
|
||||
return this._modelViewId;
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
return 'ModelViewEditorInput';
|
||||
}
|
||||
|
||||
public resolve(refresh?: boolean): TPromise<IEditorModel> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return this._title;
|
||||
}
|
||||
}
|
||||
119
src/sql/parts/modelComponents/radioButton.component.ts
Normal file
119
src/sql/parts/modelComponents/radioButton.component.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./radioButton';
|
||||
import {
|
||||
Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
||||
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList, AfterViewInit
|
||||
} from '@angular/core';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
|
||||
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||
import { RadioButton } from 'sql/base/browser/ui/radioButton/radioButton';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
|
||||
@Component({
|
||||
selector: 'radioButton',
|
||||
template: `
|
||||
<div #input class="modelview-radiobutton-container">
|
||||
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export default class RadioButtonComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
|
||||
@Input() descriptor: IComponentDescriptor;
|
||||
@Input() modelStore: IModelStore;
|
||||
private _input: RadioButton;
|
||||
|
||||
@ViewChild('input', { read: ElementRef }) private _inputContainer: ElementRef;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
|
||||
super(changeRef);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.baseInit();
|
||||
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
if (this._inputContainer) {
|
||||
this._input = new RadioButton(this._inputContainer.nativeElement, {
|
||||
label: this.label
|
||||
});
|
||||
|
||||
this._register(this._input);
|
||||
this._register(this._input.onClicked(e => {
|
||||
this._onEventEmitter.fire({
|
||||
eventType: ComponentEventType.onDidClick,
|
||||
args: e
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.baseDestroy();
|
||||
}
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
}
|
||||
|
||||
public setProperties(properties: { [key: string]: any; }): void {
|
||||
super.setProperties(properties);
|
||||
this._input.name = this.name;
|
||||
this._input.value = this.value;
|
||||
this._input.label = this.label;
|
||||
this._input.enabled = this.enabled;
|
||||
|
||||
this._input.checked = this.checked;
|
||||
}
|
||||
|
||||
// CSS-bound properties
|
||||
|
||||
public get checked(): boolean {
|
||||
return this.getPropertyOrDefault<sqlops.RadioButtonProperties, boolean>((props) => props.checked, false);
|
||||
}
|
||||
|
||||
public set value(newValue: string) {
|
||||
this.setPropertyFromUI<sqlops.RadioButtonProperties, string>((properties, value) => { properties.checked = value; }, newValue);
|
||||
}
|
||||
|
||||
public get value(): string {
|
||||
return this.getPropertyOrDefault<sqlops.RadioButtonProperties, string>((props) => props.value, '');
|
||||
}
|
||||
|
||||
public getLabel(): string {
|
||||
return this.label;
|
||||
}
|
||||
|
||||
public get label(): string {
|
||||
return this.getPropertyOrDefault<sqlops.RadioButtonProperties, string>((props) => props.label, '');
|
||||
}
|
||||
|
||||
public set label(newValue: string) {
|
||||
this.setPropertyFromUI<sqlops.RadioButtonProperties, string>((properties, label) => { properties.label = label; }, newValue);
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return this.getPropertyOrDefault<sqlops.RadioButtonProperties, string>((props) => props.name, '');
|
||||
}
|
||||
|
||||
public set name(newValue: string) {
|
||||
this.setPropertyFromUI<sqlops.RadioButtonProperties, string>((properties, label) => { properties.name = label; }, newValue);
|
||||
}
|
||||
}
|
||||
11
src/sql/parts/modelComponents/radioButton.css
Normal file
11
src/sql/parts/modelComponents/radioButton.css
Normal file
@@ -0,0 +1,11 @@
|
||||
.modelview-radiobutton-container {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.modelview-radiobutton-item {
|
||||
align-self: flex-start ;
|
||||
}
|
||||
|
||||
.modelview-radiobutton-title {
|
||||
|
||||
}
|
||||
@@ -11,9 +11,16 @@ import { NewProfilerAction } from './profilerActions';
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { ProfilerInput } from 'sql/parts/profiler/editor/profilerInput';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
|
||||
// Contribute Global Actions
|
||||
const category = nls.localize('profilerCategory', "Profiler");
|
||||
@@ -24,8 +31,27 @@ const newProfilerSchema: IJSONSchema = {
|
||||
default: null
|
||||
};
|
||||
|
||||
if (process.env['VSCODE_DEV']) {
|
||||
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewProfilerAction, GlobalNewProfilerAction.ID, GlobalNewProfilerAction.LABEL), 'Profiler: New Profiler', category);
|
||||
new NewProfilerAction().registerTask();
|
||||
}
|
||||
CommandsRegistry.registerCommand({
|
||||
id: 'profiler.newProfiler',
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
let editorService: IWorkbenchEditorService = accessor.get(IWorkbenchEditorService);
|
||||
let instantiationService: IInstantiationService = accessor.get(IInstantiationService);
|
||||
let connectionService: IConnectionManagementService = accessor.get(IConnectionManagementService);
|
||||
|
||||
// TODO: for test-only, grab the first MSSQL active connection for the profiler session
|
||||
// TODO: when finishing the feature the connection should come from the launch context
|
||||
let connectionProfile: IConnectionProfile;
|
||||
let activeConnections = connectionService.getActiveConnections();
|
||||
if (activeConnections) {
|
||||
for (let i = 0; i < activeConnections.length; ++i) {
|
||||
if (activeConnections[i].providerName === 'MSSQL') {
|
||||
connectionProfile = activeConnections[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let profilerInput = instantiationService.createInstance(ProfilerInput, connectionProfile);
|
||||
return editorService.openEditor(profilerInput, { pinned: true }, false).then(() => TPromise.as(true));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -8,14 +8,17 @@
|
||||
import * as sqlops from 'sqlops';
|
||||
import { OptionsDialog } from 'sql/base/browser/ui/modal/optionsDialog';
|
||||
import { DialogModal } from 'sql/platform/dialog/dialogModal';
|
||||
import { Dialog } from 'sql/platform/dialog/dialogTypes';
|
||||
import { WizardModal } from 'sql/platform/dialog/wizardModal';
|
||||
import { Dialog, Wizard, DialogTab } from 'sql/platform/dialog/dialogTypes';
|
||||
import { IModalOptions } from 'sql/base/browser/ui/modal/modal';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
const defaultOptions: IModalOptions = { hasBackButton: true, isWide: false };
|
||||
const defaultOptions: IModalOptions = { hasBackButton: false, isWide: false };
|
||||
const defaultWizardOptions: IModalOptions = { hasBackButton: false, isWide: true };
|
||||
|
||||
export class CustomDialogService {
|
||||
private _dialogModals = new Map<Dialog, DialogModal>();
|
||||
private _wizardModals = new Map<Wizard, WizardModal>();
|
||||
|
||||
constructor( @IInstantiationService private _instantiationService: IInstantiationService) { }
|
||||
|
||||
@@ -26,10 +29,24 @@ export class CustomDialogService {
|
||||
dialogModal.open();
|
||||
}
|
||||
|
||||
public showWizard(wizard: Wizard, options?: IModalOptions): void {
|
||||
let wizardModal = this._instantiationService.createInstance(WizardModal, wizard, 'WizardPage', options || defaultWizardOptions);
|
||||
this._wizardModals.set(wizard, wizardModal);
|
||||
wizardModal.render();
|
||||
wizardModal.open();
|
||||
}
|
||||
|
||||
public closeDialog(dialog: Dialog): void {
|
||||
let dialogModal = this._dialogModals.get(dialog);
|
||||
if (dialogModal) {
|
||||
dialogModal.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public closeWizard(wizard: Wizard): void {
|
||||
let wizardModal = this._wizardModals.get(wizard);
|
||||
if (wizardModal) {
|
||||
wizardModal.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,8 @@ export class DialogModal extends Modal {
|
||||
body = bodyBuilder.getHTMLElement();
|
||||
});
|
||||
|
||||
this._dialogPane = new DialogPane(this._dialog, this._bootstrapService);
|
||||
this._dialogPane = new DialogPane(this._dialog.title, this._dialog.content,
|
||||
valid => this._dialog.notifyValidityChanged(valid), this._bootstrapService);
|
||||
this._dialogPane.createBody(body);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import 'vs/css!./media/dialogModal';
|
||||
import { NgModuleRef } from '@angular/core';
|
||||
import { IModalDialogStyles } from 'sql/base/browser/ui/modal/modal';
|
||||
import { Dialog } from 'sql/platform/dialog/dialogTypes';
|
||||
import { Dialog, DialogTab } from 'sql/platform/dialog/dialogTypes';
|
||||
import { TabbedPanel, IPanelTab, IPanelView } from 'sql/base/browser/ui/panel/panel';
|
||||
import { IBootstrapService } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { DialogModule } from 'sql/platform/dialog/dialog.module';
|
||||
@@ -32,7 +32,9 @@ export class DialogPane extends Disposable implements IThemable {
|
||||
private _tabContent: HTMLElement[];
|
||||
|
||||
constructor(
|
||||
private _dialog: Dialog,
|
||||
private _title: string,
|
||||
private _content: string | DialogTab[],
|
||||
private _validityChangedCallback: (valid: boolean) => void,
|
||||
private _bootstrapService: IBootstrapService
|
||||
) {
|
||||
super();
|
||||
@@ -43,19 +45,19 @@ export class DialogPane extends Disposable implements IThemable {
|
||||
public createBody(container: HTMLElement): HTMLElement {
|
||||
new Builder(container).div({ class: 'dialogModal-pane' }, (bodyBuilder) => {
|
||||
this._body = bodyBuilder.getHTMLElement();
|
||||
if (typeof this._dialog.content === 'string' || this._dialog.content.length < 2) {
|
||||
let modelViewId = typeof this._dialog.content === 'string' ? this._dialog.content : this._dialog.content[0].content;
|
||||
if (typeof this._content === 'string' || this._content.length < 2) {
|
||||
let modelViewId = typeof this._content === 'string' ? this._content : this._content[0].content;
|
||||
this.initializeModelViewContainer(this._body, modelViewId);
|
||||
} else {
|
||||
this._tabbedPanel = new TabbedPanel(this._body);
|
||||
this._dialog.content.forEach((tab, tabIndex) => {
|
||||
this._content.forEach((tab, tabIndex) => {
|
||||
let tabContainer = document.createElement('div');
|
||||
tabContainer.style.display = 'none';
|
||||
this._body.appendChild(tabContainer);
|
||||
this.initializeModelViewContainer(tabContainer, tab.content);
|
||||
this.initializeModelViewContainer(tabContainer, tab.content, tab);
|
||||
this._tabbedPanel.pushTab({
|
||||
title: tab.title,
|
||||
identifier: 'dialogPane.' + this._dialog.title + '.' + tabIndex,
|
||||
identifier: 'dialogPane.' + this._title + '.' + tabIndex,
|
||||
view: {
|
||||
render: (container) => {
|
||||
if (tabContainer.parentElement === this._body) {
|
||||
@@ -77,14 +79,19 @@ export class DialogPane extends Disposable implements IThemable {
|
||||
/**
|
||||
* Bootstrap angular for the dialog's model view controller with the given model view ID
|
||||
*/
|
||||
private initializeModelViewContainer(bodyContainer: HTMLElement, modelViewId: string) {
|
||||
private initializeModelViewContainer(bodyContainer: HTMLElement, modelViewId: string, tab?: DialogTab) {
|
||||
this._bootstrapService.bootstrap(
|
||||
DialogModule,
|
||||
bodyContainer,
|
||||
'dialog-modelview-container',
|
||||
{
|
||||
modelViewId: modelViewId,
|
||||
validityChangedCallback: (valid: boolean) => this._setValidity(modelViewId, valid)
|
||||
validityChangedCallback: (valid: boolean) => {
|
||||
this._setValidity(modelViewId, valid);
|
||||
if (tab) {
|
||||
tab.notifyValidityChanged(valid);
|
||||
}
|
||||
}
|
||||
} as DialogComponentParams,
|
||||
undefined,
|
||||
(moduleRef) => this._moduleRefs.push(moduleRef));
|
||||
@@ -111,7 +118,7 @@ export class DialogPane extends Disposable implements IThemable {
|
||||
this._modelViewValidityMap.set(modelViewId, valid);
|
||||
let newValidity = this.isValid();
|
||||
if (newValidity !== oldValidity) {
|
||||
this._dialog.notifyValidityChanged(newValidity);
|
||||
this._validityChangedCallback(newValidity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +130,7 @@ export class DialogPane extends Disposable implements IThemable {
|
||||
|
||||
public dispose() {
|
||||
super.dispose();
|
||||
this._body.remove();
|
||||
this._moduleRefs.forEach(moduleRef => moduleRef.destroy());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,17 +9,35 @@ import * as sqlops from 'sqlops';
|
||||
import { localize } from 'vs/nls';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export class DialogTab {
|
||||
export class ModelViewPane {
|
||||
private _valid: boolean = true;
|
||||
private _validityChangedEmitter = new Emitter<boolean>();
|
||||
public readonly onValidityChanged = this._validityChangedEmitter.event;
|
||||
|
||||
public get valid(): boolean {
|
||||
return this._valid;
|
||||
}
|
||||
|
||||
public notifyValidityChanged(valid: boolean) {
|
||||
if (this._valid !== valid) {
|
||||
this._valid = valid;
|
||||
this._validityChangedEmitter.fire(this._valid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class DialogTab extends ModelViewPane {
|
||||
public content: string;
|
||||
|
||||
constructor(public title: string, content?: string) {
|
||||
super();
|
||||
if (content) {
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Dialog {
|
||||
export class Dialog extends ModelViewPane {
|
||||
private static readonly DONE_BUTTON_LABEL = localize('dialogModalDoneButtonLabel', 'Done');
|
||||
private static readonly CANCEL_BUTTON_LABEL = localize('dialogModalCancelButtonLabel', 'Cancel');
|
||||
|
||||
@@ -28,24 +46,12 @@ export class Dialog {
|
||||
public cancelButton: DialogButton = new DialogButton(Dialog.CANCEL_BUTTON_LABEL, true);
|
||||
public customButtons: DialogButton[];
|
||||
|
||||
private _valid: boolean = true;
|
||||
private _validityChangedEmitter = new Emitter<boolean>();
|
||||
public readonly onValidityChanged = this._validityChangedEmitter.event;
|
||||
|
||||
constructor(public title: string, content?: string | DialogTab[]) {
|
||||
super();
|
||||
if (content) {
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
|
||||
public get valid(): boolean {
|
||||
return this._valid;
|
||||
}
|
||||
|
||||
public notifyValidityChanged(valid: boolean) {
|
||||
this._valid = valid;
|
||||
this._validityChangedEmitter.fire(valid);
|
||||
}
|
||||
}
|
||||
|
||||
export class DialogButton implements sqlops.window.modelviewdialog.Button {
|
||||
@@ -96,4 +102,93 @@ export class DialogButton implements sqlops.window.modelviewdialog.Button {
|
||||
public registerClickEvent(clickEvent: Event<void>): void {
|
||||
clickEvent(() => this._onClick.fire());
|
||||
}
|
||||
}
|
||||
|
||||
export class WizardPage extends DialogTab {
|
||||
public customButtons: DialogButton[];
|
||||
private _enabled: boolean;
|
||||
private _onUpdate: Emitter<void> = new Emitter<void>();
|
||||
public readonly onUpdate: Event<void> = this._onUpdate.event;
|
||||
|
||||
constructor(public title: string, content?: string) {
|
||||
super(title, content);
|
||||
}
|
||||
|
||||
public get enabled(): boolean {
|
||||
return this._enabled;
|
||||
}
|
||||
|
||||
public set enabled(enabled: boolean) {
|
||||
this._enabled = enabled;
|
||||
this._onUpdate.fire();
|
||||
}
|
||||
}
|
||||
|
||||
export class Wizard {
|
||||
public pages: WizardPage[];
|
||||
public nextButton: DialogButton;
|
||||
public backButton: DialogButton;
|
||||
public generateScriptButton: DialogButton;
|
||||
public doneButton: DialogButton;
|
||||
public cancelButton: DialogButton;
|
||||
public customButtons: DialogButton[];
|
||||
private _currentPage: number;
|
||||
private _pageChangedEmitter = new Emitter<sqlops.window.modelviewdialog.WizardPageChangeInfo>();
|
||||
public readonly onPageChanged = this._pageChangedEmitter.event;
|
||||
private _pageAddedEmitter = new Emitter<WizardPage>();
|
||||
public readonly onPageAdded = this._pageAddedEmitter.event;
|
||||
private _pageRemovedEmitter = new Emitter<WizardPage>();
|
||||
public readonly onPageRemoved = this._pageRemovedEmitter.event;
|
||||
|
||||
constructor(public title: string) { }
|
||||
|
||||
public get currentPage(): number {
|
||||
return this._currentPage;
|
||||
}
|
||||
|
||||
public setCurrentPage(index: number): void {
|
||||
if (index === undefined || index < 0 || index >= this.pages.length) {
|
||||
throw new Error('Index is out of bounds');
|
||||
}
|
||||
let lastPage = this._currentPage;
|
||||
this._currentPage = index;
|
||||
if (lastPage !== undefined && this._currentPage !== undefined && lastPage !== this._currentPage) {
|
||||
this._pageChangedEmitter.fire({
|
||||
lastPage: lastPage,
|
||||
newPage: this._currentPage
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public addPage(page: WizardPage, index?: number): void {
|
||||
if (index !== undefined && (index < 0 || index > this.pages.length)) {
|
||||
throw new Error('Index is out of bounds');
|
||||
}
|
||||
if (index !== undefined && this.currentPage !== undefined && index <= this.currentPage) {
|
||||
++this._currentPage;
|
||||
}
|
||||
if (index === undefined) {
|
||||
this.pages.push(page);
|
||||
} else {
|
||||
this.pages = this.pages.slice(0, index).concat([page], this.pages.slice(index));
|
||||
}
|
||||
this._pageAddedEmitter.fire(page);
|
||||
}
|
||||
|
||||
public removePage(index: number): void {
|
||||
if (index === undefined || index < 0 || index >= this.pages.length) {
|
||||
throw new Error('Index is out of bounds');
|
||||
}
|
||||
if (index === this.currentPage) {
|
||||
// Switch to the new page before deleting the current page
|
||||
let newPage = this._currentPage > 0 ? this._currentPage - 1 : this._currentPage + 1;
|
||||
this.setCurrentPage(newPage);
|
||||
}
|
||||
if (this.currentPage !== undefined && index < this.currentPage) {
|
||||
--this._currentPage;
|
||||
}
|
||||
let removedPage = this.pages[index];
|
||||
this.pages.splice(index, 1);
|
||||
this._pageRemovedEmitter.fire(removedPage);
|
||||
}
|
||||
}
|
||||
@@ -26,3 +26,7 @@
|
||||
.dialogModal-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.footer-button.dialogModal-hidden {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
209
src/sql/platform/dialog/wizardModal.ts
Normal file
209
src/sql/platform/dialog/wizardModal.ts
Normal file
@@ -0,0 +1,209 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 'vs/css!./media/dialogModal';
|
||||
import { Modal, IModalOptions } from 'sql/base/browser/ui/modal/modal';
|
||||
import { attachModalDialogStyler } from 'sql/common/theme/styler';
|
||||
import { Wizard, Dialog, DialogButton, WizardPage } from 'sql/platform/dialog/dialogTypes';
|
||||
import { DialogPane } from 'sql/platform/dialog/dialogPane';
|
||||
import { IBootstrapService } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { Button } from 'vs/base/browser/ui/button/button';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { Builder } from 'vs/base/browser/builder';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
|
||||
import { localize } from 'vs/nls';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export class WizardModal extends Modal {
|
||||
private _dialogPanes = new Map<WizardPage, DialogPane>();
|
||||
private _onDone = new Emitter<void>();
|
||||
private _onCancel = new Emitter<void>();
|
||||
|
||||
// Wizard HTML elements
|
||||
private _body: HTMLElement;
|
||||
|
||||
// Buttons
|
||||
private _previousButton: Button;
|
||||
private _nextButton: Button;
|
||||
private _generateScriptButton: Button;
|
||||
private _doneButton: Button;
|
||||
private _cancelButton: Button;
|
||||
|
||||
constructor(
|
||||
private _wizard: Wizard,
|
||||
name: string,
|
||||
options: IModalOptions,
|
||||
@IPartService partService: IPartService,
|
||||
@IWorkbenchThemeService private _themeService: IWorkbenchThemeService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IBootstrapService private _bootstrapService: IBootstrapService
|
||||
) {
|
||||
super(_wizard.title, name, partService, telemetryService, contextKeyService, options);
|
||||
}
|
||||
|
||||
public layout(): void {
|
||||
|
||||
}
|
||||
|
||||
public render() {
|
||||
super.render();
|
||||
attachModalDialogStyler(this, this._themeService);
|
||||
|
||||
if (this.backButton) {
|
||||
this.backButton.onDidClick(() => this.cancel());
|
||||
attachButtonStyler(this.backButton, this._themeService, { buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND });
|
||||
}
|
||||
|
||||
this._previousButton = this.addDialogButton(this._wizard.backButton, () => this.showPage(this.getCurrentPage() - 1));
|
||||
this._nextButton = this.addDialogButton(this._wizard.nextButton, () => this.showPage(this.getCurrentPage() + 1));
|
||||
this._generateScriptButton = this.addDialogButton(this._wizard.generateScriptButton, () => undefined);
|
||||
this._doneButton = this.addDialogButton(this._wizard.doneButton, () => this.done(), false);
|
||||
this._wizard.doneButton.registerClickEvent(this._onDone.event);
|
||||
this._cancelButton = this.addDialogButton(this._wizard.cancelButton, () => this.cancel(), false);
|
||||
this._wizard.cancelButton.registerClickEvent(this._onCancel.event);
|
||||
}
|
||||
|
||||
private addDialogButton(button: DialogButton, onSelect: () => void = () => undefined, registerClickEvent: boolean = true): Button {
|
||||
let buttonElement = this.addFooterButton(button.label, onSelect);
|
||||
buttonElement.enabled = button.enabled;
|
||||
if (registerClickEvent) {
|
||||
button.registerClickEvent(buttonElement.onDidClick);
|
||||
}
|
||||
button.onUpdate(() => {
|
||||
this.updateButtonElement(buttonElement, button);
|
||||
});
|
||||
attachButtonStyler(buttonElement, this._themeService);
|
||||
this.updateButtonElement(buttonElement, button);
|
||||
return buttonElement;
|
||||
}
|
||||
|
||||
private updateButtonElement(buttonElement: Button, dialogButton: DialogButton) {
|
||||
buttonElement.label = dialogButton.label;
|
||||
buttonElement.enabled = dialogButton.enabled;
|
||||
dialogButton.hidden ? buttonElement.element.classList.add('dialogModal-hidden') : buttonElement.element.classList.remove('dialogModal-hidden');
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement): void {
|
||||
new Builder(container).div({ class: 'dialogModal-body' }, (bodyBuilder) => {
|
||||
this._body = bodyBuilder.getHTMLElement();
|
||||
});
|
||||
|
||||
let builder = new Builder(this._body);
|
||||
this._wizard.pages.forEach(page => {
|
||||
this.registerPage(page);
|
||||
});
|
||||
this._wizard.onPageAdded(page => {
|
||||
this.registerPage(page);
|
||||
this.showPage(this.getCurrentPage());
|
||||
});
|
||||
this._wizard.onPageRemoved(page => {
|
||||
let dialogPane = this._dialogPanes.get(page);
|
||||
this._dialogPanes.delete(page);
|
||||
this.showPage(this.getCurrentPage());
|
||||
dialogPane.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
private registerPage(page: WizardPage): void {
|
||||
let dialogPane = new DialogPane(page.title, page.content, valid => page.notifyValidityChanged(valid), this._bootstrapService);
|
||||
dialogPane.createBody(this._body);
|
||||
this._dialogPanes.set(page, dialogPane);
|
||||
page.onUpdate(() => this.setButtonsForPage(this._wizard.currentPage));
|
||||
}
|
||||
|
||||
private showPage(index: number): void {
|
||||
let pageToShow = this._wizard.pages[index];
|
||||
if (!pageToShow) {
|
||||
this.done();
|
||||
return;
|
||||
}
|
||||
this._dialogPanes.forEach((dialogPane, page) => {
|
||||
if (page === pageToShow) {
|
||||
dialogPane.show();
|
||||
} else {
|
||||
dialogPane.hide();
|
||||
}
|
||||
});
|
||||
this.setButtonsForPage(index);
|
||||
this._wizard.setCurrentPage(index);
|
||||
}
|
||||
|
||||
private setButtonsForPage(index: number) {
|
||||
if (this._wizard.pages[index - 1]) {
|
||||
this._previousButton.element.parentElement.classList.remove('dialogModal-hidden');
|
||||
this._previousButton.enabled = this._wizard.pages[index - 1].enabled;
|
||||
} else {
|
||||
this._previousButton.element.parentElement.classList.add('dialogModal-hidden');
|
||||
}
|
||||
|
||||
if (this._wizard.pages[index + 1]) {
|
||||
this._nextButton.element.parentElement.classList.remove('dialogModal-hidden');
|
||||
this._nextButton.enabled = this._wizard.pages[index + 1].enabled;
|
||||
this._doneButton.element.parentElement.classList.add('dialogModal-hidden');
|
||||
} else {
|
||||
this._nextButton.element.parentElement.classList.add('dialogModal-hidden');
|
||||
this._doneButton.element.parentElement.classList.remove('dialogModal-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
private getCurrentPage(): number {
|
||||
return this._wizard.currentPage;
|
||||
}
|
||||
|
||||
public open(): void {
|
||||
this.showPage(0);
|
||||
this.show();
|
||||
}
|
||||
|
||||
public done(): void {
|
||||
if (this._wizard.doneButton.enabled) {
|
||||
this._onDone.fire();
|
||||
this.dispose();
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
|
||||
public cancel(): void {
|
||||
this._onCancel.fire();
|
||||
this.dispose();
|
||||
this.hide();
|
||||
}
|
||||
|
||||
protected hide(): void {
|
||||
super.hide();
|
||||
}
|
||||
|
||||
protected show(): void {
|
||||
super.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridable to change behavior of escape key
|
||||
*/
|
||||
protected onClose(e: StandardKeyboardEvent) {
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridable to change behavior of enter key
|
||||
*/
|
||||
protected onAccept(e: StandardKeyboardEvent) {
|
||||
this.done();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
this._dialogPanes.forEach(dialogPane => dialogPane.dispose());
|
||||
}
|
||||
}
|
||||
203
src/sql/sqlops.proposed.d.ts
vendored
203
src/sql/sqlops.proposed.d.ts
vendored
@@ -21,6 +21,7 @@ declare module 'sqlops' {
|
||||
card(): ComponentBuilder<CardComponent>;
|
||||
inputBox(): ComponentBuilder<InputBoxComponent>;
|
||||
checkBox(): ComponentBuilder<CheckBoxComponent>;
|
||||
radioButton(): ComponentBuilder<RadioButtonComponent>;
|
||||
button(): ComponentBuilder<ButtonComponent>;
|
||||
dropDown(): ComponentBuilder<DropDownComponent>;
|
||||
dashboardWidget(widgetId: string): ComponentBuilder<WidgetComponent>;
|
||||
@@ -44,6 +45,22 @@ declare module 'sqlops' {
|
||||
|
||||
export interface FormBuilder extends ContainerBuilder<FormContainer, FormLayout, FormItemLayout> {
|
||||
withFormItems(components: FormComponent[], itemLayout?: FormItemLayout): ContainerBuilder<FormContainer, FormLayout, FormItemLayout>;
|
||||
|
||||
/**
|
||||
* Creates a collection of child components and adds them all to this container
|
||||
*
|
||||
* @param formComponents the definitions
|
||||
* @param {*} [itemLayout] Optional layout for the child items
|
||||
*/
|
||||
addFormItems(formComponents: Array<FormComponent>, itemLayout?: FormItemLayout): void;
|
||||
|
||||
/**
|
||||
* Creates a child component and adds it to this container.
|
||||
*
|
||||
* @param formComponent the component to be added
|
||||
* @param {*} [itemLayout] Optional layout for this child item
|
||||
*/
|
||||
addFormItem(formComponent: FormComponent, itemLayout?: FormItemLayout): void;
|
||||
}
|
||||
|
||||
export interface Component {
|
||||
@@ -147,6 +164,8 @@ declare module 'sqlops' {
|
||||
* Matches the align-content CSS property.
|
||||
*/
|
||||
alignContent?: string;
|
||||
|
||||
height? : number;
|
||||
}
|
||||
|
||||
export interface FlexItemLayout {
|
||||
@@ -236,6 +255,13 @@ declare module 'sqlops' {
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export interface RadioButtonProperties {
|
||||
name?: string;
|
||||
label?: string;
|
||||
value?: string;
|
||||
checked?: boolean;
|
||||
}
|
||||
|
||||
export interface DropDownProperties {
|
||||
value?: string;
|
||||
values?: string[];
|
||||
@@ -256,6 +282,10 @@ declare module 'sqlops' {
|
||||
onTextChanged: vscode.Event<any>;
|
||||
}
|
||||
|
||||
export interface RadioButtonComponent extends Component, RadioButtonProperties {
|
||||
onDidClick: vscode.Event<any>;
|
||||
}
|
||||
|
||||
export interface CheckBoxComponent extends Component {
|
||||
checked: boolean;
|
||||
label: string;
|
||||
@@ -366,6 +396,18 @@ declare module 'sqlops' {
|
||||
*/
|
||||
export function closeDialog(dialog: Dialog): void;
|
||||
|
||||
/**
|
||||
* Create a wizard page with the given title, for inclusion in a wizard
|
||||
* @param title The title of the page
|
||||
*/
|
||||
export function createWizardPage(title: string): WizardPage;
|
||||
|
||||
/**
|
||||
* Create a wizard with the given title and pages
|
||||
* @param title The title of the wizard
|
||||
*/
|
||||
export function createWizard(title: string): Wizard;
|
||||
|
||||
export interface ModelViewPanel {
|
||||
/**
|
||||
* Register model view content for the dialog.
|
||||
@@ -377,6 +419,16 @@ declare module 'sqlops' {
|
||||
* Returns the model view content if registered. Returns undefined if model review is not registered
|
||||
*/
|
||||
readonly modelView: ModelView;
|
||||
|
||||
/**
|
||||
* Whether the panel's content is valid
|
||||
*/
|
||||
readonly valid: boolean;
|
||||
|
||||
/**
|
||||
* Fired whenever the panel's valid property changes
|
||||
*/
|
||||
readonly onValidityChanged: vscode.Event<boolean>;
|
||||
}
|
||||
|
||||
// Model view dialog classes
|
||||
@@ -406,16 +458,6 @@ declare module 'sqlops' {
|
||||
* Any additional buttons that should be displayed
|
||||
*/
|
||||
customButtons: Button[];
|
||||
|
||||
/**
|
||||
* Whether the dialog's content is valid
|
||||
*/
|
||||
readonly valid: boolean;
|
||||
|
||||
/**
|
||||
* Fired whenever the dialog's valid property changes
|
||||
*/
|
||||
readonly onValidityChanged: vscode.Event<boolean>;
|
||||
}
|
||||
|
||||
export interface DialogTab extends ModelViewPanel {
|
||||
@@ -451,6 +493,128 @@ declare module 'sqlops' {
|
||||
*/
|
||||
readonly onClick: vscode.Event<void>;
|
||||
}
|
||||
|
||||
export interface WizardPageChangeInfo {
|
||||
/**
|
||||
* The page number that the wizard changed from
|
||||
*/
|
||||
lastPage: number,
|
||||
|
||||
/**
|
||||
* The new page number
|
||||
*/
|
||||
newPage: number
|
||||
}
|
||||
|
||||
export interface WizardPage extends ModelViewPanel {
|
||||
/**
|
||||
* The title of the page
|
||||
*/
|
||||
title: string;
|
||||
|
||||
/**
|
||||
* A string giving the ID of the page's model view content
|
||||
*/
|
||||
content: string;
|
||||
|
||||
/**
|
||||
* Any additional buttons that should be displayed while the page is open
|
||||
*/
|
||||
customButtons: Button[];
|
||||
|
||||
/**
|
||||
* Whether the page is enabled. If the page is not enabled, the user will not be
|
||||
* able to advance to it. Defaults to true.
|
||||
*/
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface Wizard {
|
||||
/**
|
||||
* The title of the wizard
|
||||
*/
|
||||
title: string,
|
||||
|
||||
/**
|
||||
* The wizard's pages. Pages can be added/removed while the dialog is open by using
|
||||
* the addPage and removePage methods
|
||||
*/
|
||||
pages: WizardPage[];
|
||||
|
||||
/**
|
||||
* The index in the pages array of the active page, or undefined if the wizard is
|
||||
* not currently visible
|
||||
*/
|
||||
readonly currentPage: number;
|
||||
|
||||
/**
|
||||
* The done button
|
||||
*/
|
||||
doneButton: Button;
|
||||
|
||||
/**
|
||||
* The cancel button
|
||||
*/
|
||||
cancelButton: Button;
|
||||
|
||||
/**
|
||||
* The generate script button
|
||||
*/
|
||||
generateScriptButton: Button;
|
||||
|
||||
/**
|
||||
* The next button
|
||||
*/
|
||||
nextButton: Button;
|
||||
|
||||
/**
|
||||
* The back button
|
||||
*/
|
||||
backButton: Button;
|
||||
|
||||
/**
|
||||
* Any additional buttons that should be displayed for all pages of the dialog. If
|
||||
* buttons are needed for specific pages they can be added using the customButtons
|
||||
* property on each page.
|
||||
*/
|
||||
customButtons: Button[];
|
||||
|
||||
/**
|
||||
* Event fired when the wizard's page changes, containing information about the
|
||||
* previous page and the new page
|
||||
*/
|
||||
onPageChanged: vscode.Event<WizardPageChangeInfo>;
|
||||
|
||||
/**
|
||||
* Add a page to the wizard at the given index
|
||||
* @param page The page to add
|
||||
* @param index The index in the pages array to add the page at, or undefined to
|
||||
* add it at the end
|
||||
*/
|
||||
addPage(page: WizardPage, index?: number): Thenable<void>;
|
||||
|
||||
/**
|
||||
* Remove the page at the given index from the wizard
|
||||
* @param index The index in the pages array to remove
|
||||
*/
|
||||
removePage(index: number): Thenable<void>;
|
||||
|
||||
/**
|
||||
* Go to the page at the given index in the pages array.
|
||||
* @param index The index of the page to go to
|
||||
*/
|
||||
setCurrentPage(index: number): Thenable<void>;
|
||||
|
||||
/**
|
||||
* Open the wizard. Does nothing if the wizard is already open.
|
||||
*/
|
||||
open(): Thenable<void>;
|
||||
|
||||
/**
|
||||
* Close the wizard. Does nothing if the wizard is not open.
|
||||
*/
|
||||
close(): Thenable<void>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,4 +636,23 @@ declare module 'sqlops' {
|
||||
*/
|
||||
export function runQuery(fileUri: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Namespace for interacting with the workspace
|
||||
*/
|
||||
export namespace workspace {
|
||||
|
||||
/**
|
||||
* Create a new model view editor
|
||||
*/
|
||||
export function createModelViewEditor(title: string): ModelViewEditor;
|
||||
|
||||
export interface ModelViewEditor extends window.modelviewdialog.ModelViewPanel {
|
||||
|
||||
/**
|
||||
* Opens the editor
|
||||
*/
|
||||
openEditor(position?: vscode.ViewColumn): Thenable<void>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ export enum ModelComponentTypes {
|
||||
DropDown,
|
||||
Button,
|
||||
CheckBox,
|
||||
RadioButton,
|
||||
DashboardWidget,
|
||||
DashboardWebview,
|
||||
Form
|
||||
@@ -120,6 +121,25 @@ export interface IModelViewButtonDetails {
|
||||
hidden: boolean;
|
||||
}
|
||||
|
||||
export interface IModelViewWizardPageDetails {
|
||||
title: string;
|
||||
content: string;
|
||||
enabled: boolean;
|
||||
customButtons: number[];
|
||||
}
|
||||
|
||||
export interface IModelViewWizardDetails {
|
||||
title: string;
|
||||
pages: number[];
|
||||
currentPage: number;
|
||||
doneButton: number;
|
||||
cancelButton: number;
|
||||
generateScriptButton: number;
|
||||
nextButton: number;
|
||||
backButton: number;
|
||||
customButtons: number[];
|
||||
}
|
||||
|
||||
/// Card-related APIs that need to be here to avoid early load issues
|
||||
// with enums causing requiring of sqlops API to fail.
|
||||
export enum StatusIndicator {
|
||||
|
||||
@@ -59,6 +59,13 @@ class ModelBuilderImpl implements sqlops.ModelBuilder {
|
||||
return builder;
|
||||
}
|
||||
|
||||
radioButton(): sqlops.ComponentBuilder<sqlops.RadioButtonComponent> {
|
||||
let id = this.getNextComponentId();
|
||||
let builder: ComponentBuilderImpl<sqlops.RadioButtonComponent> = this.getComponentBuilder(new RadioButtonWrapper(this._proxy, this._handle, id), id);
|
||||
this._componentBuilders.set(id, builder);
|
||||
return builder;
|
||||
}
|
||||
|
||||
checkBox(): sqlops.ComponentBuilder<sqlops.CheckBoxComponent> {
|
||||
let id = this.getNextComponentId();
|
||||
let builder: ComponentBuilderImpl<sqlops.CheckBoxComponent> = this.getComponentBuilder(new CheckBoxWrapper(this._proxy, this._handle, id), id);
|
||||
@@ -177,36 +184,56 @@ class ContainerBuilderImpl<T extends sqlops.Component, TLayout, TItemLayout> ext
|
||||
}
|
||||
}
|
||||
|
||||
class FormContainerBuilder extends ContainerBuilderImpl<sqlops.FormContainer, sqlops.FormLayout, sqlops.FormItemLayout> {
|
||||
class FormContainerBuilder extends ContainerBuilderImpl<sqlops.FormContainer, sqlops.FormLayout, sqlops.FormItemLayout> implements sqlops.FormBuilder {
|
||||
|
||||
withFormItems(components: sqlops.FormComponent[], itemLayout?: sqlops.FormItemLayout): sqlops.ContainerBuilder<sqlops.FormContainer, sqlops.FormLayout, sqlops.FormItemLayout> {
|
||||
|
||||
this._component.itemConfigs = components.map(item => {
|
||||
let componentWrapper = item.component as ComponentWrapper;
|
||||
let actions: string[] = undefined;
|
||||
if (item.actions) {
|
||||
actions = item.actions.map(action => {
|
||||
let actionComponentWrapper = action as ComponentWrapper;
|
||||
return actionComponentWrapper.id;
|
||||
});
|
||||
}
|
||||
return new InternalItemConfig(componentWrapper, Object.assign({}, itemLayout, {
|
||||
title: item.title,
|
||||
actions: actions,
|
||||
isFormComponent: true
|
||||
}));
|
||||
return this.convertToItemConfig(item, itemLayout);
|
||||
});
|
||||
|
||||
components.forEach(formItem => {
|
||||
if (formItem.actions) {
|
||||
formItem.actions.forEach(component => {
|
||||
let componentWrapper = component as ComponentWrapper;
|
||||
this._component.itemConfigs.push(new InternalItemConfig(componentWrapper, itemLayout));
|
||||
});
|
||||
}
|
||||
this.addComponentActions(formItem, itemLayout);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
private convertToItemConfig(formComponent: sqlops.FormComponent, itemLayout?: sqlops.FormItemLayout): InternalItemConfig {
|
||||
let componentWrapper = formComponent.component as ComponentWrapper;
|
||||
let actions: string[] = undefined;
|
||||
if (formComponent.actions) {
|
||||
actions = formComponent.actions.map(action => {
|
||||
let actionComponentWrapper = action as ComponentWrapper;
|
||||
return actionComponentWrapper.id;
|
||||
});
|
||||
}
|
||||
|
||||
return new InternalItemConfig(componentWrapper, Object.assign({}, itemLayout, {
|
||||
title: formComponent.title,
|
||||
actions: actions,
|
||||
isFormComponent: true
|
||||
}));
|
||||
}
|
||||
|
||||
private addComponentActions(formComponent: sqlops.FormComponent, itemLayout?: sqlops.FormItemLayout): void {
|
||||
if (formComponent.actions) {
|
||||
formComponent.actions.forEach(component => {
|
||||
let componentWrapper = component as ComponentWrapper;
|
||||
this._component.addItem(componentWrapper, itemLayout);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addFormItems(formComponents: Array<sqlops.FormComponent>, itemLayout?: sqlops.FormItemLayout): void {
|
||||
formComponents.forEach(formComponent => {
|
||||
this.addFormItem(formComponent, itemLayout);
|
||||
});
|
||||
}
|
||||
|
||||
addFormItem(formComponent: sqlops.FormComponent, itemLayout?: sqlops.FormItemLayout): void {
|
||||
let itemImpl = this.convertToItemConfig(formComponent, itemLayout);
|
||||
this._component.addItem(formComponent.component as ComponentWrapper, itemImpl.config);
|
||||
this.addComponentActions(formComponent, itemLayout);
|
||||
}
|
||||
}
|
||||
|
||||
class InternalItemConfig {
|
||||
@@ -489,6 +516,47 @@ class CheckBoxWrapper extends ComponentWrapper implements sqlops.CheckBoxCompone
|
||||
}
|
||||
}
|
||||
|
||||
class RadioButtonWrapper extends ComponentWrapper implements sqlops.RadioButtonComponent {
|
||||
|
||||
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
|
||||
super(proxy, handle, ModelComponentTypes.RadioButton, id);
|
||||
this.properties = {};
|
||||
this._emitterMap.set(ComponentEventType.onDidClick, new Emitter<any>());
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return this.properties['name'];
|
||||
}
|
||||
public set name(v: string) {
|
||||
this.setProperty('name', v);
|
||||
}
|
||||
|
||||
public get label(): string {
|
||||
return this.properties['label'];
|
||||
}
|
||||
public set label(v: string) {
|
||||
this.setProperty('label', v);
|
||||
}
|
||||
|
||||
public get value(): string {
|
||||
return this.properties['value'];
|
||||
}
|
||||
public set value(v: string) {
|
||||
this.setProperty('value', v);
|
||||
}
|
||||
public get checked(): boolean {
|
||||
return this.properties['checked'];
|
||||
}
|
||||
public set checked(v: boolean) {
|
||||
this.setProperty('checked', v);
|
||||
}
|
||||
|
||||
public get onDidClick(): vscode.Event<any> {
|
||||
let emitter = this._emitterMap.get(ComponentEventType.onDidClick);
|
||||
return emitter && emitter.event;
|
||||
}
|
||||
}
|
||||
|
||||
class DropDownWrapper extends ComponentWrapper implements sqlops.DropDownComponent {
|
||||
|
||||
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
|
||||
|
||||
@@ -15,18 +15,29 @@ import * as sqlops from 'sqlops';
|
||||
import { SqlMainContext, ExtHostModelViewDialogShape, MainThreadModelViewDialogShape, ExtHostModelViewShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||
import { IItemConfig, ModelComponentTypes, IComponentShape } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
|
||||
const DONE_LABEL = nls.localize('dialogDoneLabel', 'Done');
|
||||
const CANCEL_LABEL = nls.localize('dialogCancelLabel', 'Cancel');
|
||||
const GENERATE_SCRIPT_LABEL = nls.localize('generateScriptLabel', 'Generate script');
|
||||
const NEXT_LABEL = nls.localize('dialogNextLabel', 'Next');
|
||||
const PREVIOUS_LABEL = nls.localize('dialogPreviousLabel', 'Previous');
|
||||
|
||||
class ModelViewPanelImpl implements sqlops.window.modelviewdialog.ModelViewPanel {
|
||||
private _modelView: sqlops.ModelView;
|
||||
private _handle: number;
|
||||
private _modelViewId: string;
|
||||
protected _modelViewId: string;
|
||||
protected _valid: boolean = true;
|
||||
protected _onValidityChanged: vscode.Event<boolean>;
|
||||
|
||||
constructor(private _viewType: string,
|
||||
protected _extHostModelViewDialog: ExtHostModelViewDialog,
|
||||
protected _extHostModelView: ExtHostModelViewShape) {
|
||||
this._onValidityChanged = this._extHostModelViewDialog.getValidityChangedEvent(this);
|
||||
this._onValidityChanged(valid => this._valid = valid);
|
||||
}
|
||||
|
||||
public registerContent(handler: (view: sqlops.ModelView) => void): void {
|
||||
if (!this._modelViewId) {
|
||||
let viewId = this._viewType + this.handle;
|
||||
let viewId = this._viewType + this._handle;
|
||||
this.setModelViewId(viewId);
|
||||
this._extHostModelView.$registerProvider(viewId, modelView => {
|
||||
this._modelView = modelView;
|
||||
@@ -50,29 +61,43 @@ class ModelViewPanelImpl implements sqlops.window.modelviewdialog.ModelViewPanel
|
||||
public set modelView(value: sqlops.ModelView) {
|
||||
this._modelView = value;
|
||||
}
|
||||
|
||||
public get valid(): boolean {
|
||||
return this._valid;
|
||||
}
|
||||
|
||||
public get onValidityChanged(): Event<boolean> {
|
||||
return this._onValidityChanged;
|
||||
}
|
||||
}
|
||||
|
||||
class DialogImpl extends ModelViewPanelImpl implements sqlops.window.modelviewdialog.Dialog {
|
||||
class ModelViewEditorImpl extends ModelViewPanelImpl implements sqlops.workspace.ModelViewEditor {
|
||||
constructor(
|
||||
extHostModelViewDialog: ExtHostModelViewDialog,
|
||||
extHostModelView: ExtHostModelViewShape,
|
||||
private _proxy: MainThreadModelViewDialogShape,
|
||||
private _title: string
|
||||
) {
|
||||
super('modelViewEditor', extHostModelViewDialog, extHostModelView);
|
||||
}
|
||||
|
||||
public openEditor(position?: vscode.ViewColumn): Thenable<void> {
|
||||
return this._proxy.$openEditor(this._modelViewId, this._title, position);
|
||||
}
|
||||
}
|
||||
|
||||
class DialogImpl extends ModelViewPanelImpl implements sqlops.window.modelviewdialog.Dialog {
|
||||
public title: string;
|
||||
public content: string | sqlops.window.modelviewdialog.DialogTab[];
|
||||
public okButton: sqlops.window.modelviewdialog.Button;
|
||||
public cancelButton: sqlops.window.modelviewdialog.Button;
|
||||
public customButtons: sqlops.window.modelviewdialog.Button[];
|
||||
public readonly onValidityChanged: vscode.Event<boolean>;
|
||||
private _valid: boolean = true;
|
||||
|
||||
|
||||
constructor(private _extHostModelViewDialog: ExtHostModelViewDialog,
|
||||
constructor(extHostModelViewDialog: ExtHostModelViewDialog,
|
||||
extHostModelView: ExtHostModelViewShape) {
|
||||
super('modelViewDialog', extHostModelView);
|
||||
this.okButton = this._extHostModelViewDialog.createButton(nls.localize('dialogOkLabel', 'Done'));
|
||||
this.cancelButton = this._extHostModelViewDialog.createButton(nls.localize('dialogCancelLabel', 'Cancel'));
|
||||
this.onValidityChanged = this._extHostModelViewDialog.getValidityChangedEvent(this);
|
||||
this.onValidityChanged(valid => this._valid = valid);
|
||||
}
|
||||
|
||||
public get valid(): boolean {
|
||||
return this._valid;
|
||||
super('modelViewDialog', extHostModelViewDialog, extHostModelView);
|
||||
this.okButton = this._extHostModelViewDialog.createButton(DONE_LABEL);
|
||||
this.cancelButton = this._extHostModelViewDialog.createButton(CANCEL_LABEL);
|
||||
}
|
||||
|
||||
public setModelViewId(value: string) {
|
||||
@@ -83,9 +108,9 @@ class DialogImpl extends ModelViewPanelImpl implements sqlops.window.modelviewdi
|
||||
|
||||
class TabImpl extends ModelViewPanelImpl implements sqlops.window.modelviewdialog.DialogTab {
|
||||
constructor(
|
||||
private _extHostModelViewDialog: ExtHostModelViewDialog,
|
||||
extHostModelViewDialog: ExtHostModelViewDialog,
|
||||
extHostModelView: ExtHostModelViewShape) {
|
||||
super('modelViewDialogTab', extHostModelView);
|
||||
super('modelViewDialogTab', extHostModelViewDialog, extHostModelView);
|
||||
}
|
||||
|
||||
public title: string;
|
||||
@@ -143,16 +168,110 @@ class ButtonImpl implements sqlops.window.modelviewdialog.Button {
|
||||
}
|
||||
}
|
||||
|
||||
class WizardPageImpl extends ModelViewPanelImpl implements sqlops.window.modelviewdialog.WizardPage {
|
||||
public customButtons: sqlops.window.modelviewdialog.Button[];
|
||||
private _enabled: boolean = true;
|
||||
|
||||
constructor(public title: string, _extHostModelViewDialog: ExtHostModelViewDialog, _extHostModelView: ExtHostModelViewShape) {
|
||||
super('modelViewWizardPage', _extHostModelViewDialog, _extHostModelView);
|
||||
}
|
||||
|
||||
public get enabled(): boolean {
|
||||
return this._enabled;
|
||||
}
|
||||
|
||||
public set enabled(enabled: boolean) {
|
||||
this._enabled = enabled;
|
||||
this._extHostModelViewDialog.updateWizardPage(this);
|
||||
}
|
||||
|
||||
public get content(): string {
|
||||
return this._modelViewId;
|
||||
}
|
||||
|
||||
public set content(content: string) {
|
||||
this._modelViewId = content;
|
||||
}
|
||||
}
|
||||
|
||||
export enum WizardPageInfoEventType {
|
||||
PageChanged,
|
||||
PageAddedOrRemoved
|
||||
}
|
||||
|
||||
export interface WizardPageEventInfo {
|
||||
eventType: WizardPageInfoEventType;
|
||||
pageChangeInfo: sqlops.window.modelviewdialog.WizardPageChangeInfo;
|
||||
pages?: sqlops.window.modelviewdialog.WizardPage[];
|
||||
}
|
||||
|
||||
class WizardImpl implements sqlops.window.modelviewdialog.Wizard {
|
||||
private _currentPage: number = undefined;
|
||||
public pages: sqlops.window.modelviewdialog.WizardPage[] = [];
|
||||
public doneButton: sqlops.window.modelviewdialog.Button;
|
||||
public cancelButton: sqlops.window.modelviewdialog.Button;
|
||||
public generateScriptButton: sqlops.window.modelviewdialog.Button;
|
||||
public nextButton: sqlops.window.modelviewdialog.Button;
|
||||
public backButton: sqlops.window.modelviewdialog.Button;
|
||||
public customButtons: sqlops.window.modelviewdialog.Button[];
|
||||
private _pageChangedEmitter = new Emitter<sqlops.window.modelviewdialog.WizardPageChangeInfo>();
|
||||
public readonly onPageChanged = this._pageChangedEmitter.event;
|
||||
|
||||
constructor(public title: string, private _extHostModelViewDialog: ExtHostModelViewDialog) {
|
||||
this.doneButton = this._extHostModelViewDialog.createButton(DONE_LABEL);
|
||||
this.cancelButton = this._extHostModelViewDialog.createButton(CANCEL_LABEL);
|
||||
this.generateScriptButton = this._extHostModelViewDialog.createButton(GENERATE_SCRIPT_LABEL);
|
||||
this.nextButton = this._extHostModelViewDialog.createButton(NEXT_LABEL);
|
||||
this.backButton = this._extHostModelViewDialog.createButton(PREVIOUS_LABEL);
|
||||
this._extHostModelViewDialog.registerWizardPageInfoChangedCallback(this, info => this.handlePageInfoChanged(info));
|
||||
this.onPageChanged(info => this._currentPage = info.newPage);
|
||||
}
|
||||
|
||||
public get currentPage(): number {
|
||||
return this._currentPage;
|
||||
}
|
||||
|
||||
public addPage(page: sqlops.window.modelviewdialog.WizardPage, index?: number): Thenable<void> {
|
||||
return this._extHostModelViewDialog.updateWizardPage(page).then(() => {
|
||||
this._extHostModelViewDialog.addPage(this, page, index);
|
||||
});
|
||||
}
|
||||
|
||||
public removePage(index: number): Thenable<void> {
|
||||
return this._extHostModelViewDialog.removePage(this, index);
|
||||
}
|
||||
|
||||
public setCurrentPage(index: number): Thenable<void> {
|
||||
return this._extHostModelViewDialog.setWizardPage(this, index);
|
||||
}
|
||||
|
||||
public open(): Thenable<void> {
|
||||
return this._extHostModelViewDialog.openWizard(this);
|
||||
}
|
||||
|
||||
public close(): Thenable<void> {
|
||||
return this._extHostModelViewDialog.closeWizard(this);
|
||||
}
|
||||
|
||||
private handlePageInfoChanged(info: WizardPageEventInfo): void {
|
||||
this._currentPage = info.pageChangeInfo.newPage;
|
||||
if (info.eventType === WizardPageInfoEventType.PageAddedOrRemoved) {
|
||||
this.pages = info.pages;
|
||||
} else if (info.eventType === WizardPageInfoEventType.PageChanged) {
|
||||
this._pageChangedEmitter.fire(info.pageChangeInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
|
||||
private static _currentHandle = 0;
|
||||
|
||||
private readonly _proxy: MainThreadModelViewDialogShape;
|
||||
|
||||
private readonly _dialogHandles = new Map<sqlops.window.modelviewdialog.Dialog, number>();
|
||||
private readonly _tabHandles = new Map<sqlops.window.modelviewdialog.DialogTab, number>();
|
||||
private readonly _buttonHandles = new Map<sqlops.window.modelviewdialog.Button, number>();
|
||||
|
||||
private readonly _objectHandles = new Map<object, number>();
|
||||
private readonly _objectsByHandle = new Map<number, object>();
|
||||
private readonly _validityEmitters = new Map<number, Emitter<boolean>>();
|
||||
private readonly _pageInfoChangedCallbacks = new Map<number, (info: WizardPageEventInfo) => void>();
|
||||
private readonly _onClickCallbacks = new Map<number, () => void>();
|
||||
|
||||
constructor(
|
||||
@@ -168,29 +287,13 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
|
||||
return handle;
|
||||
}
|
||||
|
||||
private getDialogHandle(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
let handle = this._dialogHandles.get(dialog);
|
||||
private getHandle(item: sqlops.window.modelviewdialog.Button | sqlops.window.modelviewdialog.Dialog | sqlops.window.modelviewdialog.DialogTab
|
||||
| sqlops.window.modelviewdialog.ModelViewPanel | sqlops.window.modelviewdialog.Wizard | sqlops.window.modelviewdialog.WizardPage | sqlops.workspace.ModelViewEditor) {
|
||||
let handle = this._objectHandles.get(item);
|
||||
if (handle === undefined) {
|
||||
handle = ExtHostModelViewDialog.getNewHandle();
|
||||
this._dialogHandles.set(dialog, handle);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
private getTabHandle(tab: sqlops.window.modelviewdialog.DialogTab) {
|
||||
let handle = this._tabHandles.get(tab);
|
||||
if (handle === undefined) {
|
||||
handle = ExtHostModelViewDialog.getNewHandle();
|
||||
this._tabHandles.set(tab, handle);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
private getButtonHandle(button: sqlops.window.modelviewdialog.Button) {
|
||||
let handle = this._buttonHandles.get(button);
|
||||
if (handle === undefined) {
|
||||
handle = ExtHostModelViewDialog.getNewHandle();
|
||||
this._buttonHandles.set(button, handle);
|
||||
this._objectHandles.set(item, handle);
|
||||
this._objectsByHandle.set(handle, item);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
@@ -199,26 +302,57 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
|
||||
this._onClickCallbacks.get(handle)();
|
||||
}
|
||||
|
||||
public $onDialogValidityChanged(handle: number, valid: boolean): void {
|
||||
public $onPanelValidityChanged(handle: number, valid: boolean): void {
|
||||
let emitter = this._validityEmitters.get(handle);
|
||||
if (emitter) {
|
||||
emitter.fire(valid);
|
||||
}
|
||||
}
|
||||
|
||||
public open(dialog: sqlops.window.modelviewdialog.Dialog): void {
|
||||
let handle = this.getDialogHandle(dialog);
|
||||
this.updateDialogContent(dialog);
|
||||
this._proxy.$open(handle);
|
||||
public $onWizardPageChanged(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): void {
|
||||
let callback = this._pageInfoChangedCallbacks.get(handle);
|
||||
if (callback) {
|
||||
callback({
|
||||
eventType: WizardPageInfoEventType.PageChanged,
|
||||
pageChangeInfo: info
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public close(dialog: sqlops.window.modelviewdialog.Dialog): void {
|
||||
let handle = this.getDialogHandle(dialog);
|
||||
this._proxy.$close(handle);
|
||||
public $updateWizardPageInfo(handle: number, pageHandles: number[], currentPageIndex: number): void {
|
||||
let callback = this._pageInfoChangedCallbacks.get(handle);
|
||||
if (callback) {
|
||||
let pages = pageHandles.map(pageHandle => this._objectsByHandle.get(handle) as sqlops.window.modelviewdialog.WizardPage);
|
||||
callback({
|
||||
eventType: WizardPageInfoEventType.PageAddedOrRemoved,
|
||||
pageChangeInfo: {
|
||||
lastPage: undefined,
|
||||
newPage: currentPageIndex
|
||||
},
|
||||
pages: pages
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public openDialog(dialog: sqlops.window.modelviewdialog.Dialog): void {
|
||||
let handle = this.getHandle(dialog);
|
||||
this.updateDialogContent(dialog);
|
||||
this._proxy.$openDialog(handle);
|
||||
}
|
||||
|
||||
public closeDialog(dialog: sqlops.window.modelviewdialog.Dialog): void {
|
||||
let handle = this.getHandle(dialog);
|
||||
this._proxy.$closeDialog(handle);
|
||||
}
|
||||
|
||||
public createModelViewEditor(title: string): sqlops.workspace.ModelViewEditor {
|
||||
let editor = new ModelViewEditorImpl(this, this._extHostModelView, this._proxy, title);
|
||||
editor.handle = this.getHandle(editor);
|
||||
return editor;
|
||||
}
|
||||
|
||||
public updateDialogContent(dialog: sqlops.window.modelviewdialog.Dialog): void {
|
||||
let handle = this.getDialogHandle(dialog);
|
||||
let handle = this.getHandle(dialog);
|
||||
let tabs = dialog.content;
|
||||
if (tabs && typeof tabs !== 'string') {
|
||||
tabs.forEach(tab => this.updateTabContent(tab));
|
||||
@@ -230,15 +364,15 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
|
||||
this.updateButton(dialog.cancelButton);
|
||||
this._proxy.$setDialogDetails(handle, {
|
||||
title: dialog.title,
|
||||
okButton: this.getButtonHandle(dialog.okButton),
|
||||
cancelButton: this.getButtonHandle(dialog.cancelButton),
|
||||
content: dialog.content && typeof dialog.content !== 'string' ? dialog.content.map(tab => this.getTabHandle(tab)) : dialog.content as string,
|
||||
customButtons: dialog.customButtons ? dialog.customButtons.map(button => this.getButtonHandle(button)) : undefined
|
||||
okButton: this.getHandle(dialog.okButton),
|
||||
cancelButton: this.getHandle(dialog.cancelButton),
|
||||
content: dialog.content && typeof dialog.content !== 'string' ? dialog.content.map(tab => this.getHandle(tab)) : dialog.content as string,
|
||||
customButtons: dialog.customButtons ? dialog.customButtons.map(button => this.getHandle(button)) : undefined
|
||||
});
|
||||
}
|
||||
|
||||
public updateTabContent(tab: sqlops.window.modelviewdialog.DialogTab): void {
|
||||
let handle = this.getTabHandle(tab);
|
||||
let handle = this.getHandle(tab);
|
||||
this._proxy.$setTabDetails(handle, {
|
||||
title: tab.title,
|
||||
content: tab.content
|
||||
@@ -246,7 +380,7 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
|
||||
}
|
||||
|
||||
public updateButton(button: sqlops.window.modelviewdialog.Button): void {
|
||||
let handle = this.getButtonHandle(button);
|
||||
let handle = this.getHandle(button);
|
||||
this._proxy.$setButtonDetails(handle, {
|
||||
label: button.label,
|
||||
enabled: button.enabled,
|
||||
@@ -255,34 +389,34 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
|
||||
}
|
||||
|
||||
public registerOnClickCallback(button: sqlops.window.modelviewdialog.Button, callback: () => void) {
|
||||
let handle = this.getButtonHandle(button);
|
||||
let handle = this.getHandle(button);
|
||||
this._onClickCallbacks.set(handle, callback);
|
||||
}
|
||||
|
||||
public createDialog(title: string): sqlops.window.modelviewdialog.Dialog {
|
||||
let dialog = new DialogImpl(this, this._extHostModelView);
|
||||
dialog.title = title;
|
||||
dialog.handle = this.getDialogHandle(dialog);
|
||||
dialog.handle = this.getHandle(dialog);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public createTab(title: string): sqlops.window.modelviewdialog.DialogTab {
|
||||
let tab = new TabImpl(this, this._extHostModelView);
|
||||
tab.title = title;
|
||||
tab.handle = this.getTabHandle(tab);
|
||||
tab.handle = this.getHandle(tab);
|
||||
return tab;
|
||||
}
|
||||
|
||||
public createButton(label: string): sqlops.window.modelviewdialog.Button {
|
||||
let button = new ButtonImpl(this);
|
||||
this.getButtonHandle(button);
|
||||
this.getHandle(button);
|
||||
this.registerOnClickCallback(button, button.getOnClickCallback());
|
||||
button.label = label;
|
||||
return button;
|
||||
}
|
||||
|
||||
public getValidityChangedEvent(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
let handle = this.getDialogHandle(dialog);
|
||||
public getValidityChangedEvent(panel: sqlops.window.modelviewdialog.ModelViewPanel) {
|
||||
let handle = this.getHandle(panel);
|
||||
let emitter = this._validityEmitters.get(handle);
|
||||
if (!emitter) {
|
||||
emitter = new Emitter<boolean>();
|
||||
@@ -290,4 +424,81 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
|
||||
}
|
||||
return emitter.event;
|
||||
}
|
||||
|
||||
public registerWizardPageInfoChangedCallback(wizard: sqlops.window.modelviewdialog.Wizard, callback: (info: WizardPageEventInfo) => void): void {
|
||||
let handle = this.getHandle(wizard);
|
||||
this._pageInfoChangedCallbacks.set(handle, callback);
|
||||
}
|
||||
|
||||
public createWizardPage(title: string): sqlops.window.modelviewdialog.WizardPage {
|
||||
let page = new WizardPageImpl(title, this, this._extHostModelView);
|
||||
page.handle = this.getHandle(page);
|
||||
return page;
|
||||
}
|
||||
|
||||
public createWizard(title: string): sqlops.window.modelviewdialog.Wizard {
|
||||
let wizard = new WizardImpl(title, this);
|
||||
this.getHandle(wizard);
|
||||
return wizard;
|
||||
}
|
||||
|
||||
public updateWizardPage(page: sqlops.window.modelviewdialog.WizardPage): Thenable<void> {
|
||||
let handle = this.getHandle(page);
|
||||
if (page.customButtons) {
|
||||
page.customButtons.forEach(button => this.updateButton(button));
|
||||
}
|
||||
return this._proxy.$setWizardPageDetails(handle, {
|
||||
content: page.content,
|
||||
customButtons: page.customButtons ? page.customButtons.map(button => this.getHandle(button)) : undefined,
|
||||
enabled: page.enabled,
|
||||
title: page.title
|
||||
});
|
||||
}
|
||||
|
||||
public updateWizard(wizard: sqlops.window.modelviewdialog.Wizard): Thenable<void> {
|
||||
let handle = this.getHandle(wizard);
|
||||
wizard.pages.forEach(page => this.updateWizardPage(page));
|
||||
this.updateButton(wizard.backButton);
|
||||
this.updateButton(wizard.cancelButton);
|
||||
this.updateButton(wizard.generateScriptButton);
|
||||
this.updateButton(wizard.doneButton);
|
||||
this.updateButton(wizard.nextButton);
|
||||
if (wizard.customButtons) {
|
||||
wizard.customButtons.forEach(button => this.updateButton(button));
|
||||
}
|
||||
return this._proxy.$setWizardDetails(handle, {
|
||||
title: wizard.title,
|
||||
pages: wizard.pages.map(page => this.getHandle(page)),
|
||||
currentPage: wizard.currentPage,
|
||||
backButton: this.getHandle(wizard.backButton),
|
||||
cancelButton: this.getHandle(wizard.cancelButton),
|
||||
generateScriptButton: this.getHandle(wizard.generateScriptButton),
|
||||
doneButton: this.getHandle(wizard.doneButton),
|
||||
nextButton: this.getHandle(wizard.nextButton),
|
||||
customButtons: wizard.customButtons ? wizard.customButtons.map(button => this.getHandle(button)) : undefined
|
||||
});
|
||||
}
|
||||
|
||||
public addPage(wizard: sqlops.window.modelviewdialog.Wizard, page: sqlops.window.modelviewdialog.WizardPage, pageIndex?: number): Thenable<void> {
|
||||
return this._proxy.$addWizardPage(this.getHandle(wizard), this.getHandle(page), pageIndex);
|
||||
}
|
||||
|
||||
public removePage(wizard: sqlops.window.modelviewdialog.Wizard, pageIndex: number): Thenable<void> {
|
||||
return this._proxy.$removeWizardPage(this.getHandle(wizard), pageIndex);
|
||||
}
|
||||
|
||||
public setWizardPage(wizard: sqlops.window.modelviewdialog.Wizard, pageIndex: number): Thenable<void> {
|
||||
return this._proxy.$setWizardPage(this.getHandle(wizard), pageIndex);
|
||||
}
|
||||
|
||||
public openWizard(wizard: sqlops.window.modelviewdialog.Wizard): Thenable<void> {
|
||||
let handle = this.getHandle(wizard);
|
||||
this.updateWizard(wizard);
|
||||
return this._proxy.$openWizard(handle);
|
||||
}
|
||||
|
||||
public closeWizard(wizard: sqlops.window.modelviewdialog.Wizard): Thenable<void> {
|
||||
let handle = this.getHandle(wizard);
|
||||
return this._proxy.$closeWizard(handle);
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,13 @@
|
||||
import { MainThreadModelViewShape, SqlMainContext, ExtHostModelViewShape, SqlExtHostContext } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
import { IModelViewService } from 'sql/services/modelComponents/modelViewService';
|
||||
import { IItemConfig, ModelComponentTypes, IComponentShape } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { IModelView } from 'sql/services/model/modelViewService';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
|
||||
@extHostNamedCustomer(SqlMainContext.MainThreadModelView)
|
||||
|
||||
@@ -4,13 +4,19 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { MainThreadModelViewDialogShape, SqlMainContext, ExtHostModelViewDialogShape, SqlExtHostContext } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||
import { Dialog, DialogTab, DialogButton } from 'sql/platform/dialog/dialogTypes';
|
||||
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { CustomDialogService } from 'sql/platform/dialog/customDialogService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IModelViewDialogDetails, IModelViewTabDetails, IModelViewButtonDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
|
||||
import { MainThreadModelViewDialogShape, SqlMainContext, ExtHostModelViewDialogShape, SqlExtHostContext } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||
import { Dialog, DialogTab, DialogButton, WizardPage, Wizard } from 'sql/platform/dialog/dialogTypes';
|
||||
import { CustomDialogService } from 'sql/platform/dialog/customDialogService';
|
||||
import { IModelViewDialogDetails, IModelViewTabDetails, IModelViewButtonDetails, IModelViewWizardPageDetails, IModelViewWizardDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { ModelViewInput } from 'sql/parts/modelComponents/modelEditor/modelViewInput';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
@extHostNamedCustomer(SqlMainContext.MainThreadModelViewDialog)
|
||||
export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape {
|
||||
@@ -18,11 +24,15 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
||||
private readonly _dialogs = new Map<number, Dialog>();
|
||||
private readonly _tabs = new Map<number, DialogTab>();
|
||||
private readonly _buttons = new Map<number, DialogButton>();
|
||||
private readonly _wizardPages = new Map<number, WizardPage>();
|
||||
private readonly _wizardPageHandles = new Map<WizardPage, number>();
|
||||
private readonly _wizards = new Map<number, Wizard>();
|
||||
private _dialogService: CustomDialogService;
|
||||
|
||||
constructor(
|
||||
context: IExtHostContext,
|
||||
@IInstantiationService instatiationService: IInstantiationService,
|
||||
@IWorkbenchEditorService private _editorService: IWorkbenchEditorService
|
||||
) {
|
||||
this._proxy = context.getProxy(SqlExtHostContext.ExtHostModelViewDialog);
|
||||
this._dialogService = new CustomDialogService(instatiationService);
|
||||
@@ -32,13 +42,29 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
public $open(handle: number): Thenable<void> {
|
||||
public $openEditor(modelViewId: string, title: string, position?: vscode.ViewColumn): Thenable<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let input = new ModelViewInput(title, modelViewId);
|
||||
let editorOptions = {
|
||||
preserveFocus: true,
|
||||
pinned: true
|
||||
};
|
||||
|
||||
this._editorService.openEditor(input, editorOptions, position as any).then(() => {
|
||||
resolve();
|
||||
}, error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public $openDialog(handle: number): Thenable<void> {
|
||||
let dialog = this.getDialog(handle);
|
||||
this._dialogService.showDialog(dialog);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public $close(handle: number): Thenable<void> {
|
||||
public $closeDialog(handle: number): Thenable<void> {
|
||||
let dialog = this.getDialog(handle);
|
||||
this._dialogService.closeDialog(dialog);
|
||||
return Promise.resolve();
|
||||
@@ -52,7 +78,7 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
||||
let cancelButton = this.getButton(details.cancelButton);
|
||||
dialog.okButton = okButton;
|
||||
dialog.cancelButton = cancelButton;
|
||||
dialog.onValidityChanged(valid => this._proxy.$onDialogValidityChanged(handle, valid));
|
||||
dialog.onValidityChanged(valid => this._proxy.$onPanelValidityChanged(handle, valid));
|
||||
this._dialogs.set(handle, dialog);
|
||||
}
|
||||
|
||||
@@ -74,6 +100,7 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
||||
let tab = this._tabs.get(handle);
|
||||
if (!tab) {
|
||||
tab = new DialogTab(details.title);
|
||||
tab.onValidityChanged(valid => this._proxy.$onPanelValidityChanged(handle, valid));
|
||||
this._tabs.set(handle, tab);
|
||||
}
|
||||
|
||||
@@ -98,12 +125,91 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public $setWizardPageDetails(handle: number, details: IModelViewWizardPageDetails): Thenable<void> {
|
||||
let page = this._wizardPages.get(handle);
|
||||
if (!page) {
|
||||
page = new WizardPage(details.title, details.content);
|
||||
page.onValidityChanged(valid => this._proxy.$onPanelValidityChanged(handle, valid));
|
||||
this._wizardPages.set(handle, page);
|
||||
this._wizardPageHandles.set(page, handle);
|
||||
}
|
||||
|
||||
page.title = details.title;
|
||||
page.content = details.content;
|
||||
page.enabled = details.enabled;
|
||||
if (details.customButtons !== undefined) {
|
||||
page.customButtons = details.customButtons.map(buttonHandle => this.getButton(buttonHandle));
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public $setWizardDetails(handle: number, details: IModelViewWizardDetails): Thenable<void> {
|
||||
let wizard = this._wizards.get(handle);
|
||||
if (!wizard) {
|
||||
wizard = new Wizard(details.title);
|
||||
wizard.backButton = this.getButton(details.backButton);
|
||||
wizard.cancelButton = this.getButton(details.cancelButton);
|
||||
wizard.generateScriptButton = this.getButton(details.generateScriptButton);
|
||||
wizard.doneButton = this.getButton(details.doneButton);
|
||||
wizard.nextButton = this.getButton(details.nextButton);
|
||||
wizard.onPageChanged(info => this._proxy.$onWizardPageChanged(handle, info));
|
||||
wizard.onPageAdded(() => this.handleWizardPageAddedOrRemoved(handle));
|
||||
wizard.onPageRemoved(() => this.handleWizardPageAddedOrRemoved(handle));
|
||||
this._wizards.set(handle, wizard);
|
||||
}
|
||||
|
||||
wizard.title = details.title;
|
||||
wizard.pages = details.pages.map(handle => this.getWizardPage(handle));
|
||||
if (details.currentPage !== undefined) {
|
||||
wizard.setCurrentPage(details.currentPage);
|
||||
}
|
||||
if (details.customButtons !== undefined) {
|
||||
wizard.customButtons = details.customButtons.map(buttonHandle => this.getButton(buttonHandle));
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public $addWizardPage(wizardHandle: number, pageHandle: number, pageIndex?: number): Thenable<void> {
|
||||
if (pageIndex === null) {
|
||||
pageIndex = undefined;
|
||||
}
|
||||
let wizard = this.getWizard(wizardHandle);
|
||||
let page = this.getWizardPage(pageHandle);
|
||||
wizard.addPage(page, pageIndex);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public $removeWizardPage(wizardHandle: number, pageIndex: number): Thenable<void> {
|
||||
let wizard = this.getWizard(wizardHandle);
|
||||
wizard.removePage(pageIndex);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public $setWizardPage(wizardHandle: number, pageIndex: number): Thenable<void> {
|
||||
let wizard = this.getWizard(wizardHandle);
|
||||
wizard.setCurrentPage(pageIndex);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public $openWizard(handle: number): Thenable<void> {
|
||||
let wizard = this.getWizard(handle);
|
||||
this._dialogService.showWizard(wizard);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public $closeWizard(handle: number): Thenable<void> {
|
||||
let wizard = this.getWizard(handle);
|
||||
this._dialogService.closeWizard(wizard);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
private getDialog(handle: number): Dialog {
|
||||
let dialog = this._dialogs.get(handle);
|
||||
if (!dialog) {
|
||||
throw new Error('No dialog matching the given handle');
|
||||
}
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@@ -112,7 +218,6 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
||||
if (!tab) {
|
||||
throw new Error('No tab matching the given handle');
|
||||
}
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
@@ -121,11 +226,31 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
||||
if (!button) {
|
||||
throw new Error('No button matching the given handle');
|
||||
}
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
private onButtonClick(handle: number): void {
|
||||
this._proxy.$onButtonClick(handle);
|
||||
}
|
||||
|
||||
private getWizardPage(handle: number): WizardPage {
|
||||
let page = this._wizardPages.get(handle);
|
||||
if (!page) {
|
||||
throw new Error('No page matching the given handle');
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
private getWizard(handle: number): Wizard {
|
||||
let wizard = this._wizards.get(handle);
|
||||
if (!wizard) {
|
||||
throw new Error('No wizard matching the given handle');
|
||||
}
|
||||
return wizard;
|
||||
}
|
||||
|
||||
private handleWizardPageAddedOrRemoved(handle: number): void {
|
||||
let wizard = this._wizards.get(handle);
|
||||
this._proxy.$updateWizardPageInfo(handle, wizard.pages.map(page => this._wizardPageHandles.get(page)), wizard.currentPage);
|
||||
}
|
||||
}
|
||||
@@ -295,10 +295,16 @@ export function createApiFactory(
|
||||
return extHostModelViewDialog.createButton(label);
|
||||
},
|
||||
openDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
return extHostModelViewDialog.open(dialog);
|
||||
return extHostModelViewDialog.openDialog(dialog);
|
||||
},
|
||||
closeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
return extHostModelViewDialog.close(dialog);
|
||||
return extHostModelViewDialog.closeDialog(dialog);
|
||||
},
|
||||
createWizardPage(title: string): sqlops.window.modelviewdialog.WizardPage {
|
||||
return extHostModelViewDialog.createWizardPage(title);
|
||||
},
|
||||
createWizard(title: string): sqlops.window.modelviewdialog.Wizard {
|
||||
return extHostModelViewDialog.createWizard(title);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -318,7 +324,10 @@ export function createApiFactory(
|
||||
|
||||
const workspace: typeof sqlops.workspace = {
|
||||
onDidOpenDashboard: extHostDashboard.onDidOpenDashboard,
|
||||
onDidChangeToDashboard: extHostDashboard.onDidChangeToDashboard
|
||||
onDidChangeToDashboard: extHostDashboard.onDidChangeToDashboard,
|
||||
createModelViewEditor(title: string): sqlops.workspace.ModelViewEditor {
|
||||
return extHostModelViewDialog.createModelViewEditor(title);
|
||||
}
|
||||
};
|
||||
|
||||
const dashboard = {
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
import {
|
||||
createMainContextProxyIdentifier as createMainId,
|
||||
createExtHostContextProxyIdentifier as createExtId,
|
||||
ProxyIdentifier, IRPCProtocol } from 'vs/workbench/services/extensions/node/proxyIdentifier';
|
||||
ProxyIdentifier, IRPCProtocol
|
||||
} from 'vs/workbench/services/extensions/node/proxyIdentifier';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
@@ -16,7 +17,10 @@ import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import { ITaskHandlerDescription } from 'sql/platform/tasks/common/tasks';
|
||||
import { IItemConfig, ModelComponentTypes, IComponentShape, IModelViewDialogDetails, IModelViewTabDetails, IModelViewButtonDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import {
|
||||
IItemConfig, ModelComponentTypes, IComponentShape, IModelViewDialogDetails, IModelViewTabDetails, IModelViewButtonDetails,
|
||||
IModelViewWizardDetails, IModelViewWizardPageDetails
|
||||
} from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export abstract class ExtHostAccountManagementShape {
|
||||
@@ -313,17 +317,17 @@ export abstract class ExtHostDataProtocolShape {
|
||||
/**
|
||||
* Get Agent Job list
|
||||
*/
|
||||
$getJobs(handle: number, ownerUri: string): Thenable<sqlops.AgentJobsResult>{ throw ni(); }
|
||||
$getJobs(handle: number, ownerUri: string): Thenable<sqlops.AgentJobsResult> { throw ni(); }
|
||||
|
||||
/**
|
||||
* Get a Agent Job's history
|
||||
*/
|
||||
$getJobHistory(handle: number, ownerUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult>{ throw ni(); }
|
||||
$getJobHistory(handle: number, ownerUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> { throw ni(); }
|
||||
|
||||
/**
|
||||
* Run an action on a Job
|
||||
*/
|
||||
$jobAction(handle: number, ownerUri: string, jobName: string, action: string): Thenable<sqlops.AgentJobActionResult>{ throw ni(); }
|
||||
$jobAction(handle: number, ownerUri: string, jobName: string, action: string): Thenable<sqlops.AgentJobActionResult> { throw ni(); }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -530,7 +534,7 @@ export interface MainThreadModelViewShape extends IDisposable {
|
||||
$addToContainer(handle: number, containerId: string, item: IItemConfig): Thenable<void>;
|
||||
$setLayout(handle: number, componentId: string, layout: any): Thenable<void>;
|
||||
$setProperties(handle: number, componentId: string, properties: { [key: string]: any }): Thenable<void>;
|
||||
$registerEvent(handle: number, componentId: string): Thenable<void>;
|
||||
$registerEvent(handle: number, componentId: string): Thenable<void>;
|
||||
$validate(handle: number, componentId: string): Thenable<boolean>;
|
||||
}
|
||||
|
||||
@@ -539,7 +543,7 @@ export interface ExtHostObjectExplorerShape {
|
||||
|
||||
export interface MainThreadObjectExplorerShape extends IDisposable {
|
||||
$getNode(connectionId: string, nodePath?: string): Thenable<sqlops.NodeInfo>;
|
||||
$getActiveConnectionNodes(): Thenable<{ nodeInfo: sqlops.NodeInfo, connectionId: string}[]>;
|
||||
$getActiveConnectionNodes(): Thenable<{ nodeInfo: sqlops.NodeInfo, connectionId: string }[]>;
|
||||
$setExpandedState(connectionId: string, nodePath: string, expandedState: vscode.TreeItemCollapsibleState): Thenable<void>;
|
||||
$setSelected(connectionId: string, nodePath: string, selected: boolean, clearOtherSelections?: boolean): Thenable<void>;
|
||||
$getChildren(connectionId: string, nodePath: string): Thenable<sqlops.NodeInfo[]>;
|
||||
@@ -549,15 +553,25 @@ export interface MainThreadObjectExplorerShape extends IDisposable {
|
||||
|
||||
export interface ExtHostModelViewDialogShape {
|
||||
$onButtonClick(handle: number): void;
|
||||
$onDialogValidityChanged(handle: number, valid: boolean): void;
|
||||
$onPanelValidityChanged(handle: number, valid: boolean): void;
|
||||
$onWizardPageChanged(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): void;
|
||||
$updateWizardPageInfo(handle: number, pageHandles: number[], currentPageIndex: number): void;
|
||||
}
|
||||
|
||||
export interface MainThreadModelViewDialogShape extends IDisposable {
|
||||
$open(handle: number): Thenable<void>;
|
||||
$close(handle: number): Thenable<void>;
|
||||
$openEditor(modelViewId: string, title: string, position?: vscode.ViewColumn): Thenable<void>;
|
||||
$openDialog(handle: number): Thenable<void>;
|
||||
$closeDialog(handle: number): Thenable<void>;
|
||||
$setDialogDetails(handle: number, details: IModelViewDialogDetails): Thenable<void>;
|
||||
$setTabDetails(handle: number, details: IModelViewTabDetails): Thenable<void>;
|
||||
$setButtonDetails(handle: number, details: IModelViewButtonDetails): Thenable<void>;
|
||||
$openWizard(handle: number): Thenable<void>;
|
||||
$closeWizard(handle: number): Thenable<void>;
|
||||
$setWizardPageDetails(handle: number, details: IModelViewWizardPageDetails): Thenable<void>;
|
||||
$setWizardDetails(handle: number, details: IModelViewWizardDetails): Thenable<void>;
|
||||
$addWizardPage(wizardHandle: number, pageHandle: number, pageIndex: number): Thenable<void>;
|
||||
$removeWizardPage(wizardHandle: number, pageIndex: number): Thenable<void>;
|
||||
$setWizardPage(wizardHandle: number, pageIndex: number): Thenable<void>;
|
||||
}
|
||||
export interface ExtHostQueryEditorShape {
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ suite('Dialog Pane Tests', () => {
|
||||
// If I fill in a dialog's content with the ID of a specific model view provider and then render the dialog
|
||||
let modelViewId = 'test_content';
|
||||
dialog.content = modelViewId;
|
||||
let dialogPane = new DialogPane(dialog, mockBootstrapService.object);
|
||||
let dialogPane = new DialogPane(dialog.title, dialog.content, () => undefined, mockBootstrapService.object);
|
||||
dialogPane.createBody(container);
|
||||
|
||||
// Then a single dialog-modelview-container element is added directly to the dialog pane
|
||||
@@ -47,7 +47,7 @@ suite('Dialog Pane Tests', () => {
|
||||
// If I fill in a dialog's content with a single tab and then render the dialog
|
||||
let modelViewId = 'test_content';
|
||||
dialog.content = [new DialogTab('', modelViewId)];
|
||||
let dialogPane = new DialogPane(dialog, mockBootstrapService.object);
|
||||
let dialogPane = new DialogPane(dialog.title, dialog.content, () => undefined, mockBootstrapService.object);
|
||||
dialogPane.createBody(container);
|
||||
|
||||
// Then a single dialog-modelview-container element is added directly to the dialog pane
|
||||
@@ -65,7 +65,7 @@ suite('Dialog Pane Tests', () => {
|
||||
let modelViewId1 = 'test_content_1';
|
||||
let modelViewId2 = 'test_content_2';
|
||||
dialog.content = [new DialogTab('tab1', modelViewId1), new DialogTab('tab2', modelViewId2)];
|
||||
let dialogPane = new DialogPane(dialog, mockBootstrapService.object);
|
||||
let dialogPane = new DialogPane(dialog.title, dialog.content, () => undefined, mockBootstrapService.object);
|
||||
dialogPane.createBody(container);
|
||||
|
||||
// Then a dialog-modelview-container element is added for the first tab (subsequent ones get added when the tab is actually clicked)
|
||||
@@ -90,7 +90,7 @@ suite('Dialog Pane Tests', () => {
|
||||
let modelViewId1 = 'test_content_1';
|
||||
let modelViewId2 = 'test_content_2';
|
||||
dialog.content = [new DialogTab('tab1', modelViewId1), new DialogTab('tab2', modelViewId2)];
|
||||
let dialogPane = new DialogPane(dialog, mockBootstrapService.object);
|
||||
let dialogPane = new DialogPane(dialog.title, dialog.content, valid => dialog.notifyValidityChanged(valid), mockBootstrapService.object);
|
||||
dialogPane.createBody(container);
|
||||
|
||||
let validityChanges: boolean[] = [];
|
||||
@@ -114,7 +114,7 @@ suite('Dialog Pane Tests', () => {
|
||||
|
||||
// If I set tab 1's validation to false
|
||||
validationCallbacks[0](false);
|
||||
|
||||
|
||||
// Then the whole dialog's validation is false
|
||||
assert.equal(dialog.valid, false);
|
||||
assert.equal(validityChanges.length, 3);
|
||||
|
||||
@@ -18,17 +18,21 @@ suite('ExtHostModelViewDialog Tests', () => {
|
||||
|
||||
setup(() => {
|
||||
mockProxy = Mock.ofInstance(<MainThreadModelViewDialogShape>{
|
||||
$open: handle => undefined,
|
||||
$close: handle => undefined,
|
||||
$openDialog: handle => undefined,
|
||||
$closeDialog: handle => undefined,
|
||||
$setDialogDetails: (handle, details) => undefined,
|
||||
$setTabDetails: (handle, details) => undefined,
|
||||
$setButtonDetails: (handle, details) => undefined
|
||||
$setButtonDetails: (handle, details) => undefined,
|
||||
$openWizard: handle => undefined,
|
||||
$closeWizard: handle => undefined,
|
||||
$setWizardPageDetails: (handle, details) => undefined,
|
||||
$setWizardDetails: (handle, details) => undefined
|
||||
});
|
||||
let mainContext = <IMainContext>{
|
||||
getProxy: proxyType => mockProxy.object
|
||||
};
|
||||
|
||||
extHostModelView = Mock.ofInstance(<ExtHostModelViewShape> {
|
||||
extHostModelView = Mock.ofInstance(<ExtHostModelViewShape>{
|
||||
$registerProvider: (widget, handler) => undefined
|
||||
});
|
||||
extHostModelViewDialog = new ExtHostModelViewDialog(mainContext, extHostModelView.object);
|
||||
@@ -59,7 +63,7 @@ suite('ExtHostModelViewDialog Tests', () => {
|
||||
});
|
||||
|
||||
test('Opening a dialog updates its tabs and buttons on the main thread', () => {
|
||||
mockProxy.setup(x => x.$open(It.isAny()));
|
||||
mockProxy.setup(x => x.$openDialog(It.isAny()));
|
||||
mockProxy.setup(x => x.$setDialogDetails(It.isAny(), It.isAny()));
|
||||
mockProxy.setup(x => x.$setTabDetails(It.isAny(), It.isAny()));
|
||||
mockProxy.setup(x => x.$setButtonDetails(It.isAny(), It.isAny()));
|
||||
@@ -77,25 +81,26 @@ suite('ExtHostModelViewDialog Tests', () => {
|
||||
button1.enabled = false;
|
||||
let button2Label = 'button_2';
|
||||
let button2 = extHostModelViewDialog.createButton(button2Label);
|
||||
dialog.customButtons = [button1, button2];
|
||||
|
||||
// Open the dialog and verify that the correct main thread methods were called
|
||||
extHostModelViewDialog.open(dialog);
|
||||
extHostModelViewDialog.openDialog(dialog);
|
||||
mockProxy.verify(x => x.$setButtonDetails(It.isAny(), It.is(details => {
|
||||
return details.enabled === false && details.label === button1Label;
|
||||
})), Times.once());
|
||||
})), Times.atLeastOnce());
|
||||
mockProxy.verify(x => x.$setButtonDetails(It.isAny(), It.is(details => {
|
||||
return details.enabled === true && details.label === button2Label;
|
||||
})), Times.once());
|
||||
})), Times.atLeastOnce());
|
||||
mockProxy.verify(x => x.$setTabDetails(It.isAny(), It.is(details => {
|
||||
return details.title === tab1Title;
|
||||
})), Times.once());
|
||||
})), Times.atLeastOnce());
|
||||
mockProxy.verify(x => x.$setTabDetails(It.isAny(), It.is(details => {
|
||||
return details.title === tab2Title;
|
||||
})), Times.once());
|
||||
})), Times.atLeastOnce());
|
||||
mockProxy.verify(x => x.$setDialogDetails(It.isAny(), It.is(details => {
|
||||
return details.title === dialogTitle;
|
||||
})), Times.once());
|
||||
mockProxy.verify(x => x.$open(It.isAny()), Times.once());
|
||||
return details.title === dialogTitle && details.content.length === 2 && details.customButtons.length === 2;
|
||||
})), Times.atLeastOnce());
|
||||
mockProxy.verify(x => x.$openDialog(It.isAny()), Times.once());
|
||||
});
|
||||
|
||||
test('Button clicks are forwarded to the correct button', () => {
|
||||
@@ -123,4 +128,139 @@ suite('ExtHostModelViewDialog Tests', () => {
|
||||
// Then the clicks should have been handled by the expected handlers
|
||||
assert.deepEqual(clickEvents, [1, 2, 2, 1]);
|
||||
});
|
||||
|
||||
test('Creating a wizard returns a wizard with initialized buttons and the given title', () => {
|
||||
let title = 'wizard_title';
|
||||
let wizard = extHostModelViewDialog.createWizard(title);
|
||||
|
||||
assert.equal(wizard.title, title);
|
||||
assert.equal(wizard.doneButton.enabled, true);
|
||||
assert.equal(wizard.cancelButton.enabled, true);
|
||||
assert.equal(wizard.nextButton.enabled, true);
|
||||
assert.equal(wizard.backButton.enabled, true);
|
||||
assert.deepEqual(wizard.pages, []);
|
||||
});
|
||||
|
||||
test('Opening a wizard updates its pages and buttons on the main thread', () => {
|
||||
mockProxy.setup(x => x.$openWizard(It.isAny()));
|
||||
mockProxy.setup(x => x.$setWizardDetails(It.isAny(), It.isAny()));
|
||||
mockProxy.setup(x => x.$setWizardPageDetails(It.isAny(), It.isAny()));
|
||||
mockProxy.setup(x => x.$setButtonDetails(It.isAny(), It.isAny()));
|
||||
|
||||
// Create a wizard with 2 pages and 2 custom buttons
|
||||
let wizardTitle = 'wizard_title';
|
||||
let wizard = extHostModelViewDialog.createWizard(wizardTitle);
|
||||
let page1Title = 'page_1';
|
||||
let page1 = extHostModelViewDialog.createWizardPage(page1Title);
|
||||
let page2Title = 'page_2';
|
||||
let page2 = extHostModelViewDialog.createWizardPage(page2Title);
|
||||
wizard.pages = [page1, page2];
|
||||
let button1Label = 'button_1';
|
||||
let button1 = extHostModelViewDialog.createButton(button1Label);
|
||||
button1.enabled = false;
|
||||
let button2Label = 'button_2';
|
||||
let button2 = extHostModelViewDialog.createButton(button2Label);
|
||||
wizard.customButtons = [button1, button2];
|
||||
|
||||
// Open the wizard and verify that the correct main thread methods were called
|
||||
extHostModelViewDialog.openWizard(wizard);
|
||||
mockProxy.verify(x => x.$setButtonDetails(It.isAny(), It.is(details => {
|
||||
return details.enabled === false && details.label === button1Label;
|
||||
})), Times.atLeastOnce());
|
||||
mockProxy.verify(x => x.$setButtonDetails(It.isAny(), It.is(details => {
|
||||
return details.enabled === true && details.label === button2Label;
|
||||
})), Times.atLeastOnce());
|
||||
mockProxy.verify(x => x.$setWizardPageDetails(It.isAny(), It.is(details => {
|
||||
return details.title === page1Title;
|
||||
})), Times.atLeastOnce());
|
||||
mockProxy.verify(x => x.$setWizardPageDetails(It.isAny(), It.is(details => {
|
||||
return details.title === page2Title;
|
||||
})), Times.atLeastOnce());
|
||||
mockProxy.verify(x => x.$setWizardDetails(It.isAny(), It.is(details => {
|
||||
return details.title === wizardTitle && details.pages.length === 2 && details.customButtons.length === 2;
|
||||
})), Times.atLeastOnce());
|
||||
mockProxy.verify(x => x.$openWizard(It.isAny()), Times.once());
|
||||
});
|
||||
|
||||
test('Wizard page changed events are handled correctly', () => {
|
||||
// Set up the main thread mock to record the handle assigned to the wizard
|
||||
let wizardHandle: number;
|
||||
mockProxy.setup(x => x.$setWizardDetails(It.isAny(), It.isAny())).callback((handle, details) => wizardHandle = handle);
|
||||
|
||||
// Set up the wizard with 2 pages
|
||||
let wizard = extHostModelViewDialog.createWizard('test_wizard');
|
||||
let page1 = extHostModelViewDialog.createWizardPage('page_1');
|
||||
let page2 = extHostModelViewDialog.createWizardPage('page_2');
|
||||
wizard.pages = [page1, page2];
|
||||
extHostModelViewDialog.updateWizard(wizard);
|
||||
|
||||
// Record page changed events
|
||||
let actualPageChangeInfo = [];
|
||||
wizard.onPageChanged(pageChangeInfo => {
|
||||
actualPageChangeInfo.push(pageChangeInfo);
|
||||
});
|
||||
|
||||
// Call the page changed event and verify that it was handled
|
||||
let expectedPageChangeInfo = {
|
||||
lastPage: 0,
|
||||
newPage: 1
|
||||
};
|
||||
extHostModelViewDialog.$onWizardPageChanged(wizardHandle, expectedPageChangeInfo);
|
||||
assert.equal(actualPageChangeInfo.length, 1);
|
||||
assert.equal(actualPageChangeInfo[0], expectedPageChangeInfo);
|
||||
assert.equal(wizard.currentPage, expectedPageChangeInfo.newPage);
|
||||
});
|
||||
|
||||
test('Validity changed events are handled correctly', () => {
|
||||
// Set up the main thread mock to record handles assigned to tabs
|
||||
let tabHandles = [];
|
||||
mockProxy.setup(x => x.$setTabDetails(It.isAny(), It.isAny())).callback((handle, details) => tabHandles.push(handle));
|
||||
|
||||
// Set up the dialog with 2 tabs
|
||||
let dialog = extHostModelViewDialog.createDialog('test_dialog');
|
||||
let tab1 = extHostModelViewDialog.createTab('tab_1');
|
||||
let tab2 = extHostModelViewDialog.createTab('tab_2');
|
||||
dialog.content = [tab1, tab2];
|
||||
extHostModelViewDialog.updateDialogContent(dialog);
|
||||
|
||||
// Record tab validity changed events
|
||||
let tab1ValidityChangedEvents = [];
|
||||
let tab2ValidityChangedEvents = [];
|
||||
tab1.onValidityChanged(valid => tab1ValidityChangedEvents.push(valid));
|
||||
tab2.onValidityChanged(valid => tab2ValidityChangedEvents.push(valid));
|
||||
|
||||
// Call the validity changed event on tab 2 and verify that it was handled but tab 1 is still not valid
|
||||
extHostModelViewDialog.$onPanelValidityChanged(tabHandles[1], false);
|
||||
assert.equal(tab1ValidityChangedEvents.length, 0);
|
||||
assert.equal(tab1.valid, true);
|
||||
assert.equal(tab2ValidityChangedEvents.length, 1);
|
||||
assert.equal(tab2ValidityChangedEvents[0], false);
|
||||
assert.equal(tab2.valid, false);
|
||||
});
|
||||
|
||||
test('Verify validity changed events update validity for all panel types', () => {
|
||||
// Set up the main thread mock to record handles for the tab, dialog, and page
|
||||
let tabHandle: number;
|
||||
let dialogHandle: number;
|
||||
let pageHandle: number;
|
||||
mockProxy.setup(x => x.$setTabDetails(It.isAny(), It.isAny())).callback((handle, details) => tabHandle = handle);
|
||||
mockProxy.setup(x => x.$setDialogDetails(It.isAny(), It.isAny())).callback((handle, details) => dialogHandle = handle);
|
||||
mockProxy.setup(x => x.$setWizardPageDetails(It.isAny(), It.isAny())).callback((handle, details) => pageHandle = handle);
|
||||
|
||||
// Initialize a tab, dialog, and page
|
||||
let tab = extHostModelViewDialog.createTab('tab_1');
|
||||
extHostModelViewDialog.updateTabContent(tab);
|
||||
let dialog = extHostModelViewDialog.createDialog('dialog_1');
|
||||
extHostModelViewDialog.updateDialogContent(dialog);
|
||||
let page = extHostModelViewDialog.createWizardPage('page_1');
|
||||
extHostModelViewDialog.updateWizardPage(page);
|
||||
|
||||
// Call the validity changed event on each object and verify that the object's validity was updated
|
||||
extHostModelViewDialog.$onPanelValidityChanged(tabHandle, false);
|
||||
assert.equal(tab.valid, false);
|
||||
extHostModelViewDialog.$onPanelValidityChanged(dialogHandle, false);
|
||||
assert.equal(dialog.valid, false);
|
||||
extHostModelViewDialog.$onPanelValidityChanged(pageHandle, false);
|
||||
assert.equal(page.valid, false);
|
||||
});
|
||||
});
|
||||
@@ -7,9 +7,9 @@ import * as assert from 'assert';
|
||||
import { Mock, It, Times } from 'typemoq';
|
||||
import { MainThreadModelViewDialog } from 'sql/workbench/api/node/mainThreadModelViewDialog';
|
||||
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { IModelViewButtonDetails, IModelViewTabDetails, IModelViewDialogDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { IModelViewButtonDetails, IModelViewTabDetails, IModelViewDialogDetails, IModelViewWizardPageDetails, IModelViewWizardDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { CustomDialogService } from 'sql/platform/dialog/customDialogService';
|
||||
import { Dialog, DialogTab } from 'sql/platform/dialog/dialogTypes';
|
||||
import { Dialog, DialogTab, Wizard } from 'sql/platform/dialog/dialogTypes';
|
||||
import { ExtHostModelViewDialogShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
@@ -20,6 +20,7 @@ suite('MainThreadModelViewDialog Tests', () => {
|
||||
let mockExtHostModelViewDialog: Mock<ExtHostModelViewDialogShape>;
|
||||
let mockDialogService: Mock<CustomDialogService>;
|
||||
let openedDialog: Dialog;
|
||||
let openedWizard: Wizard;
|
||||
|
||||
// Dialog details
|
||||
let button1Details: IModelViewButtonDetails;
|
||||
@@ -37,19 +38,43 @@ suite('MainThreadModelViewDialog Tests', () => {
|
||||
let tab2Handle = 6;
|
||||
let dialogHandle = 7;
|
||||
|
||||
// Wizard details
|
||||
let nextButtonDetails: IModelViewButtonDetails;
|
||||
let backButtonDetails: IModelViewButtonDetails;
|
||||
let generateScriptButtonDetails: IModelViewButtonDetails;
|
||||
let page1Details: IModelViewWizardPageDetails;
|
||||
let page2Details: IModelViewWizardPageDetails;
|
||||
let page3Details: IModelViewWizardPageDetails;
|
||||
let wizardDetails: IModelViewWizardDetails;
|
||||
let nextButtonHandle = 8;
|
||||
let backButtonHandle = 9;
|
||||
let generateScriptButtonHandle = 10;
|
||||
let page1Handle = 11;
|
||||
let page2Handle = 12;
|
||||
let wizardHandle = 13;
|
||||
let page3Handle = 14;
|
||||
|
||||
setup(() => {
|
||||
mockExtHostModelViewDialog = Mock.ofInstance(<ExtHostModelViewDialogShape>{
|
||||
$onButtonClick: handle => undefined
|
||||
$onButtonClick: handle => undefined,
|
||||
$onPanelValidityChanged: (handle, valid) => undefined,
|
||||
$onWizardPageChanged: (handle, info) => undefined,
|
||||
$updateWizardPageInfo: (wizardHandle, pageHandles, currentPageIndex) => undefined
|
||||
});
|
||||
let extHostContext = <IExtHostContext>{
|
||||
getProxy: proxyType => mockExtHostModelViewDialog.object
|
||||
};
|
||||
mainThreadModelViewDialog = new MainThreadModelViewDialog(extHostContext, undefined);
|
||||
mainThreadModelViewDialog = new MainThreadModelViewDialog(extHostContext, undefined, undefined);
|
||||
|
||||
// Set up the mock dialog service
|
||||
mockDialogService = Mock.ofType(CustomDialogService, undefined, undefined);
|
||||
openedDialog = undefined;
|
||||
mockDialogService.setup(x => x.showDialog(It.isAny())).callback(dialog => openedDialog = dialog);
|
||||
mockDialogService.setup(x => x.showWizard(It.isAny())).callback(wizard => {
|
||||
openedWizard = wizard;
|
||||
// The actual service will set the page to 0 when it opens the wizard
|
||||
openedWizard.setCurrentPage(0);
|
||||
});
|
||||
(mainThreadModelViewDialog as any)._dialogService = mockDialogService.object;
|
||||
|
||||
// Set up the dialog details
|
||||
@@ -89,6 +114,46 @@ suite('MainThreadModelViewDialog Tests', () => {
|
||||
customButtons: [button1Handle, button2Handle]
|
||||
};
|
||||
|
||||
// Set up the wizard details
|
||||
nextButtonDetails = {
|
||||
label: 'next_label',
|
||||
enabled: true,
|
||||
hidden: false
|
||||
};
|
||||
backButtonDetails = {
|
||||
label: 'back_label',
|
||||
enabled: true,
|
||||
hidden: false
|
||||
};
|
||||
generateScriptButtonDetails = {
|
||||
label: 'generate_script_label',
|
||||
enabled: true,
|
||||
hidden: false
|
||||
};
|
||||
page1Details = {
|
||||
title: 'page1',
|
||||
content: 'content1',
|
||||
enabled: true,
|
||||
customButtons: []
|
||||
};
|
||||
page2Details = {
|
||||
title: 'page2',
|
||||
content: 'content2',
|
||||
enabled: true,
|
||||
customButtons: [button1Handle, button2Handle]
|
||||
};
|
||||
wizardDetails = {
|
||||
backButton: backButtonHandle,
|
||||
nextButton: nextButtonHandle,
|
||||
generateScriptButton: generateScriptButtonHandle,
|
||||
cancelButton: cancelButtonHandle,
|
||||
doneButton: okButtonHandle,
|
||||
currentPage: undefined,
|
||||
title: 'wizard_title',
|
||||
customButtons: [],
|
||||
pages: [page1Handle, page2Handle]
|
||||
};
|
||||
|
||||
// Register the buttons, tabs, and dialog
|
||||
mainThreadModelViewDialog.$setButtonDetails(button1Handle, button1Details);
|
||||
mainThreadModelViewDialog.$setButtonDetails(button2Handle, button2Details);
|
||||
@@ -97,11 +162,19 @@ suite('MainThreadModelViewDialog Tests', () => {
|
||||
mainThreadModelViewDialog.$setTabDetails(tab1Handle, tab1Details);
|
||||
mainThreadModelViewDialog.$setTabDetails(tab2Handle, tab2Details);
|
||||
mainThreadModelViewDialog.$setDialogDetails(dialogHandle, dialogDetails);
|
||||
|
||||
// Register the wizard and its pages and buttons
|
||||
mainThreadModelViewDialog.$setButtonDetails(nextButtonHandle, nextButtonDetails);
|
||||
mainThreadModelViewDialog.$setButtonDetails(backButtonHandle, backButtonDetails);
|
||||
mainThreadModelViewDialog.$setButtonDetails(generateScriptButtonHandle, generateScriptButtonDetails);
|
||||
mainThreadModelViewDialog.$setWizardPageDetails(page1Handle, page1Details);
|
||||
mainThreadModelViewDialog.$setWizardPageDetails(page2Handle, page2Details);
|
||||
mainThreadModelViewDialog.$setWizardDetails(wizardHandle, wizardDetails);
|
||||
});
|
||||
|
||||
test('Creating a dialog and calling open on it causes a dialog with correct content and buttons to open', () => {
|
||||
// If I open the dialog
|
||||
mainThreadModelViewDialog.$open(dialogHandle);
|
||||
mainThreadModelViewDialog.$openDialog(dialogHandle);
|
||||
|
||||
// Then the opened dialog's content and buttons match what was set
|
||||
mockDialogService.verify(x => x.showDialog(It.isAny()), Times.once());
|
||||
@@ -129,7 +202,7 @@ suite('MainThreadModelViewDialog Tests', () => {
|
||||
mockExtHostModelViewDialog.setup(x => x.$onButtonClick(It.isAny())).callback(handle => pressedHandles.push(handle));
|
||||
|
||||
// Open the dialog so that its buttons can be accessed
|
||||
mainThreadModelViewDialog.$open(dialogHandle);
|
||||
mainThreadModelViewDialog.$openDialog(dialogHandle);
|
||||
|
||||
// Set up click emitters for each button
|
||||
let okEmitter = new Emitter<void>();
|
||||
@@ -154,4 +227,93 @@ suite('MainThreadModelViewDialog Tests', () => {
|
||||
// Verify that the correct button click notifications were sent to the proxy
|
||||
assert.deepEqual(pressedHandles, [button1Handle, button2Handle, okButtonHandle, cancelButtonHandle, button2Handle, cancelButtonHandle, button1Handle, okButtonHandle]);
|
||||
});
|
||||
|
||||
test('Creating a wizard and calling open on it causes a wizard with correct pages and buttons to open', () => {
|
||||
// If I open the wizard
|
||||
mainThreadModelViewDialog.$openWizard(wizardHandle);
|
||||
|
||||
// Then the opened wizard's content and buttons match what was set
|
||||
mockDialogService.verify(x => x.showWizard(It.isAny()), Times.once());
|
||||
assert.notEqual(openedWizard, undefined);
|
||||
assert.equal(openedWizard.title, wizardDetails.title);
|
||||
assert.equal(openedWizard.doneButton.label, okButtonDetails.label);
|
||||
assert.equal(openedWizard.doneButton.enabled, okButtonDetails.enabled);
|
||||
assert.equal(openedWizard.cancelButton.label, cancelButtonDetails.label);
|
||||
assert.equal(openedWizard.cancelButton.enabled, cancelButtonDetails.enabled);
|
||||
assert.equal(openedWizard.customButtons.length, 0);
|
||||
assert.equal(openedWizard.pages.length, 2);
|
||||
assert.equal(openedWizard.currentPage, 0);
|
||||
let page1 = openedWizard.pages[0];
|
||||
assert.equal(page1.title, page1Details.title);
|
||||
assert.equal(page1.content, page1Details.content);
|
||||
assert.equal(page1.enabled, page1Details.enabled);
|
||||
assert.equal(page1.valid, true);
|
||||
assert.equal(page1.customButtons.length, 0);
|
||||
let page2 = openedWizard.pages[1];
|
||||
assert.equal(page2.title, page2Details.title);
|
||||
assert.equal(page2.content, page2Details.content);
|
||||
assert.equal(page2.enabled, page2Details.enabled);
|
||||
assert.equal(page2.valid, true);
|
||||
assert.equal(page2.customButtons.length, 2);
|
||||
});
|
||||
|
||||
test('The extension host gets notified when wizard page change events occur', () => {
|
||||
mockExtHostModelViewDialog.setup(x => x.$onWizardPageChanged(It.isAny(), It.isAny()));
|
||||
|
||||
// If I open the wizard and change the page to index 1
|
||||
mainThreadModelViewDialog.$openWizard(wizardHandle);
|
||||
openedWizard.setCurrentPage(1);
|
||||
|
||||
// Then a page changed event gets sent to the extension host
|
||||
mockExtHostModelViewDialog.verify(x => x.$onWizardPageChanged(It.is(handle => handle === wizardHandle),
|
||||
It.is(pageChangeInfo => pageChangeInfo.lastPage === 0 && pageChangeInfo.newPage === 1)), Times.once());
|
||||
});
|
||||
|
||||
test('Validity changed events are forwarded to the extension host', () => {
|
||||
mockExtHostModelViewDialog.setup(x => x.$onPanelValidityChanged(It.isAny(), It.isAny()));
|
||||
|
||||
// If I open the dialog and set its validity and its 2nd tab's validity to false
|
||||
mainThreadModelViewDialog.$openDialog(dialogHandle);
|
||||
(openedDialog.content[1] as DialogTab).notifyValidityChanged(false);
|
||||
openedDialog.notifyValidityChanged(false);
|
||||
|
||||
// Then a validity changed event gets sent to the extension host for the tab and the dialog
|
||||
mockExtHostModelViewDialog.verify(x => x.$onPanelValidityChanged(It.is(handle => handle === dialogHandle), It.is(valid => valid === false)), Times.once());
|
||||
mockExtHostModelViewDialog.verify(x => x.$onPanelValidityChanged(It.is(handle => handle === tab2Handle), It.is(valid => valid === false)), Times.once());
|
||||
});
|
||||
|
||||
test('addWizardPage method inserts pages at the correct spot and notifies the extension host', () => {
|
||||
mockExtHostModelViewDialog.setup(x => x.$updateWizardPageInfo(It.isAny(), It.isAny(), It.isAny()));
|
||||
page3Details = {
|
||||
title: 'page_3',
|
||||
content: 'content_3',
|
||||
customButtons: [],
|
||||
enabled: true
|
||||
};
|
||||
|
||||
// If I open the wizard and then add a page
|
||||
mainThreadModelViewDialog.$openWizard(wizardHandle);
|
||||
mainThreadModelViewDialog.$setWizardPageDetails(page3Handle, page3Details);
|
||||
mainThreadModelViewDialog.$addWizardPage(wizardHandle, page3Handle, 0);
|
||||
|
||||
// Then the updated page info gets sent to the extension host
|
||||
mockExtHostModelViewDialog.verify(x => x.$updateWizardPageInfo(
|
||||
It.is(handle => handle === wizardHandle),
|
||||
It.is(pageHandles => pageHandles.length === 3 && pageHandles[0] === page3Handle),
|
||||
It.is(currentPage => currentPage === 1)), Times.once());
|
||||
});
|
||||
|
||||
test('removeWizardPage method removes pages at the correct spot and notifies the extension host', () => {
|
||||
mockExtHostModelViewDialog.setup(x => x.$updateWizardPageInfo(It.isAny(), It.isAny(), It.isAny()));
|
||||
|
||||
// If I open the wizard and then remove a page
|
||||
mainThreadModelViewDialog.$openWizard(wizardHandle);
|
||||
mainThreadModelViewDialog.$removeWizardPage(wizardHandle, 0);
|
||||
|
||||
// Then the updated page info gets sent to the extension host
|
||||
mockExtHostModelViewDialog.verify(x => x.$updateWizardPageInfo(
|
||||
It.is(handle => handle === wizardHandle),
|
||||
It.is(pageHandles => pageHandles.length === 1 && pageHandles[0] === page2Handle),
|
||||
It.is(currentPage => currentPage === 0)), Times.once());
|
||||
});
|
||||
});
|
||||
@@ -1285,7 +1285,8 @@ class ScreenReaderDetectedExplanation {
|
||||
}));
|
||||
domNode.appendChild(closeBtn);
|
||||
|
||||
const question = $('p.question', {}, nls.localize('screenReaderDetectedExplanation.question', "Are you using a screen reader to operate VS Code?"));
|
||||
// {{SQL CARBON EDIT}}
|
||||
const question = $('p.question', {}, nls.localize('screenReaderDetectedExplanation.question', "Are you using a screen reader to operate SQL Operations Studio?"));
|
||||
domNode.appendChild(question);
|
||||
|
||||
const buttonContainer = $('div.buttons');
|
||||
@@ -1317,7 +1318,8 @@ class ScreenReaderDetectedExplanation {
|
||||
const hr = $('hr');
|
||||
domNode.appendChild(hr);
|
||||
|
||||
const explanation1 = $('p.body1', {}, nls.localize('screenReaderDetectedExplanation.body1', "VS Code is now optimized for usage with a screen reader."));
|
||||
// {{SQL CARBON EDIT}}
|
||||
const explanation1 = $('p.body1', {}, nls.localize('screenReaderDetectedExplanation.body1', "SQL Operations Studio is now optimized for usage with a screen reader."));
|
||||
domNode.appendChild(explanation1);
|
||||
|
||||
const explanation2 = $('p.body2', {}, nls.localize('screenReaderDetectedExplanation.body2', "Some editor features will have different behaviour: e.g. word wrapping, folding, etc."));
|
||||
|
||||
@@ -170,6 +170,8 @@ import 'sql/parts/dashboard/widgets/webview/webviewWidget.contribution';
|
||||
import 'sql/parts/dashboard/dashboardConfig.contribution';
|
||||
/* Model-based Views */
|
||||
import 'sql/parts/modelComponents/components.contribution';
|
||||
/* View Model Editor */
|
||||
import 'sql/parts/modelComponents/modelEditor/modelViewEditor.contribution';
|
||||
/* Containers */
|
||||
import 'sql/parts/dashboard/containers/dashboardWebviewContainer.contribution';
|
||||
import 'sql/parts/dashboard/containers/dashboardControlHostContainer.contribution';
|
||||
|
||||
@@ -5945,9 +5945,9 @@ slice-ansi@0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
|
||||
|
||||
"slickgrid@github:anthonydresser/SlickGrid#2.3.16":
|
||||
version "2.3.16"
|
||||
resolved "https://codeload.github.com/anthonydresser/SlickGrid/tar.gz/0cdbb91ca4f24e296e156b704dab51ea9e1cf3ac"
|
||||
"slickgrid@github:anthonydresser/SlickGrid#2.3.17":
|
||||
version "2.3.17"
|
||||
resolved "https://codeload.github.com/anthonydresser/SlickGrid/tar.gz/8def7636409c51a10890209f90083bb2c3092b3b"
|
||||
dependencies:
|
||||
jquery ">=1.8.0"
|
||||
jquery-ui ">=1.8.0"
|
||||
|
||||
Reference in New Issue
Block a user