mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-19 11:01:38 -05:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
216b6eecc0 | ||
|
|
c0917e9276 | ||
|
|
0bbcbf0d2d | ||
|
|
9b998e3fca | ||
|
|
d7d65cdf21 | ||
|
|
27925289d4 | ||
|
|
03ea265bab | ||
|
|
917f9eead3 | ||
|
|
08f2e72af8 | ||
|
|
a2fb0ec029 | ||
|
|
084042ad13 | ||
|
|
8da3defe24 | ||
|
|
58f9cd32a5 | ||
|
|
f7abf5a2d5 | ||
|
|
c8c6d072f6 | ||
|
|
4d9cc604b9 | ||
|
|
1dc76fa171 | ||
|
|
1d37b9ae9c | ||
|
|
26828602a8 | ||
|
|
e253f3ac89 | ||
|
|
4d59fdea1b | ||
|
|
98a313eb5b | ||
|
|
77e1cd8b32 | ||
|
|
dede5c5ef5 | ||
|
|
d156c0be3d | ||
|
|
dc0bc6e606 | ||
|
|
05040425df | ||
|
|
36f7c283b8 | ||
|
|
9fe4237033 | ||
|
|
b03c0a3e2d | ||
|
|
87946996ed | ||
|
|
cc55023440 | ||
|
|
1f19dfc50d | ||
|
|
950a440350 | ||
|
|
c92b88bfaf | ||
|
|
10875f26dc | ||
|
|
d62e809c18 | ||
|
|
d85bf4f6dd | ||
|
|
801e201cc3 | ||
|
|
e18e0da0c1 | ||
|
|
d046b0a412 | ||
|
|
72084b8fc1 | ||
|
|
2639b2bd2c | ||
|
|
82aa493dfd | ||
|
|
6c3c7c40b5 | ||
|
|
5616751c04 | ||
|
|
7d898ca34d | ||
|
|
e26556b21a | ||
|
|
89e6d363e2 | ||
|
|
c559ac7be9 | ||
|
|
b3fbe47f0a | ||
|
|
c73af4c480 | ||
|
|
8887fe1eac | ||
|
|
ed861a6c96 | ||
|
|
e63bb6a8ec | ||
|
|
8ec09d25ce | ||
|
|
a9a01ae479 | ||
|
|
31a3864789 | ||
|
|
a5c537197c | ||
|
|
4ea13bdbc0 | ||
|
|
b06ddf2dc7 | ||
|
|
2c45ac9df3 | ||
|
|
7735f68502 | ||
|
|
ffb0f5a1c7 | ||
|
|
80c7f9e855 | ||
|
|
709ef4e39f | ||
|
|
4ceb869420 | ||
|
|
432a209184 | ||
|
|
8444271c58 | ||
|
|
2bc97c23d4 |
2
.yarnrc
2
.yarnrc
@@ -1,3 +1,3 @@
|
|||||||
disturl "https://atom.io/download/electron"
|
disturl "https://atom.io/download/electron"
|
||||||
target "2.0.7"
|
target "2.0.9"
|
||||||
runtime "electron"
|
runtime "electron"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"azure-storage": "^2.1.0",
|
"azure-storage": "^2.1.0",
|
||||||
"decompress": "^4.2.0",
|
"decompress": "^4.2.0",
|
||||||
"documentdb": "1.13.0",
|
"documentdb": "1.13.0",
|
||||||
"service-downloader": "github:anthonydresser/service-downloader#0.1.2",
|
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
|
||||||
"fs-extra-promise": "^1.0.1",
|
"fs-extra-promise": "^1.0.1",
|
||||||
"mime": "^1.3.4",
|
"mime": "^1.3.4",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
|
|||||||
@@ -1002,7 +1002,7 @@ hoek@4.x.x:
|
|||||||
version "4.2.1"
|
version "4.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb"
|
resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb"
|
||||||
|
|
||||||
http-proxy-agent@^2.0.0:
|
http-proxy-agent@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
|
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1025,7 +1025,7 @@ http-signature@~1.2.0:
|
|||||||
jsprim "^1.2.2"
|
jsprim "^1.2.2"
|
||||||
sshpk "^1.7.0"
|
sshpk "^1.7.0"
|
||||||
|
|
||||||
https-proxy-agent@^2.1.1:
|
https-proxy-agent@^2.2.1:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1843,14 +1843,14 @@ semver@^5.4.1:
|
|||||||
version "5.5.0"
|
version "5.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||||
|
|
||||||
"service-downloader@github:anthonydresser/service-downloader#0.1.2":
|
"service-downloader@github:anthonydresser/service-downloader#0.1.5":
|
||||||
version "0.1.2"
|
version "0.1.5"
|
||||||
resolved "https://codeload.github.com/anthonydresser/service-downloader/tar.gz/2aa9b336b6442e17e24693ddc907030575539798"
|
resolved "https://codeload.github.com/anthonydresser/service-downloader/tar.gz/6ebb0465573cc140e461a22f334260f55ef45546"
|
||||||
dependencies:
|
dependencies:
|
||||||
decompress "^4.2.0"
|
decompress "^4.2.0"
|
||||||
eventemitter2 "^5.0.1"
|
eventemitter2 "^5.0.1"
|
||||||
http-proxy-agent "^2.0.0"
|
http-proxy-agent "^2.1.0"
|
||||||
https-proxy-agent "^2.1.1"
|
https-proxy-agent "^2.2.1"
|
||||||
mkdirp "^0.5.1"
|
mkdirp "^0.5.1"
|
||||||
tmp "^0.0.33"
|
tmp "^0.0.33"
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ let localize = nls.loadMessageBundle();
|
|||||||
|
|
||||||
export class AzureAccountProviderService implements vscode.Disposable {
|
export class AzureAccountProviderService implements vscode.Disposable {
|
||||||
// CONSTANTS ///////////////////////////////////////////////////////////////
|
// CONSTANTS ///////////////////////////////////////////////////////////////
|
||||||
private static CommandClearTokenCache = 'accounts.azure.clearTokenCache';
|
private static CommandClearTokenCache = 'accounts.clearTokenCache';
|
||||||
private static ConfigurationSection = 'accounts.azure';
|
private static ConfigurationSection = 'accounts.azure';
|
||||||
private static CredentialNamespace = 'azureAccountProviderCredentials';
|
private static CredentialNamespace = 'azureAccountProviderCredentials';
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
import { ExtensionContext, workspace, window, Disposable, commands, Uri, OutputChannel } from 'vscode';
|
import { ExtensionContext, workspace, window, Disposable, commands, OutputChannel } from 'vscode';
|
||||||
import { findGit, Git, IGit } from './git';
|
import { findGit, Git, IGit } from './git';
|
||||||
import { Model } from './model';
|
import { Model } from './model';
|
||||||
import { CommandCenter } from './commands';
|
import { CommandCenter } from './commands';
|
||||||
@@ -98,28 +98,29 @@ export async function activate(context: ExtensionContext): Promise<API> {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = workspace.getConfiguration('git');
|
// {{SQL CARBON EDIT}} turn-off Git missing prompt
|
||||||
const shouldIgnore = config.get<boolean>('ignoreMissingGitWarning') === true;
|
//const config = workspace.getConfiguration('git');
|
||||||
|
//const shouldIgnore = config.get<boolean>('ignoreMissingGitWarning') === true;
|
||||||
|
|
||||||
if (!shouldIgnore) {
|
// if (!shouldIgnore) {
|
||||||
console.warn(err.message);
|
// console.warn(err.message);
|
||||||
outputChannel.appendLine(err.message);
|
// outputChannel.appendLine(err.message);
|
||||||
outputChannel.show();
|
// outputChannel.show();
|
||||||
|
|
||||||
const download = localize('downloadgit', "Download Git");
|
// const download = localize('downloadgit', "Download Git");
|
||||||
const neverShowAgain = localize('neverShowAgain', "Don't Show Again");
|
// const neverShowAgain = localize('neverShowAgain', "Don't Show Again");
|
||||||
const choice = await window.showWarningMessage(
|
// const choice = await window.showWarningMessage(
|
||||||
localize('notfound', "Git not found. Install it or configure it using the 'git.path' setting."),
|
// localize('notfound', "Git not found. Install it or configure it using the 'git.path' setting."),
|
||||||
download,
|
// download,
|
||||||
neverShowAgain
|
// neverShowAgain
|
||||||
);
|
// );
|
||||||
|
|
||||||
if (choice === download) {
|
// if (choice === download) {
|
||||||
commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/'));
|
// commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/'));
|
||||||
} else if (choice === neverShowAgain) {
|
// } else if (choice === neverShowAgain) {
|
||||||
await config.update('ignoreMissingGitWarning', true, true);
|
// await config.update('ignoreMissingGitWarning', true, true);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return new NoopAPIImpl();
|
return new NoopAPIImpl();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.7",
|
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.7",
|
||||||
"opener": "^1.4.3",
|
"opener": "^1.4.3",
|
||||||
"service-downloader": "github:anthonydresser/service-downloader#0.1.4",
|
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
|
||||||
"vscode-extension-telemetry": "^0.0.5",
|
"vscode-extension-telemetry": "^0.0.5",
|
||||||
"vscode-nls": "^3.2.1"
|
"vscode-nls": "^3.2.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -177,14 +177,14 @@ graceful-fs@^4.1.10:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||||
|
|
||||||
http-proxy-agent@^2.0.0:
|
http-proxy-agent@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
|
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base "4"
|
agent-base "4"
|
||||||
debug "3.1.0"
|
debug "3.1.0"
|
||||||
|
|
||||||
https-proxy-agent@^2.1.1:
|
https-proxy-agent@^2.2.1:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -297,14 +297,14 @@ seek-bzip@^1.0.5:
|
|||||||
dependencies:
|
dependencies:
|
||||||
commander "~2.8.1"
|
commander "~2.8.1"
|
||||||
|
|
||||||
"service-downloader@github:anthonydresser/service-downloader#0.1.4":
|
"service-downloader@github:anthonydresser/service-downloader#0.1.5":
|
||||||
version "0.1.4"
|
version "0.1.5"
|
||||||
resolved "https://codeload.github.com/anthonydresser/service-downloader/tar.gz/3c0abdf8603aca85d2eacfac3c547173e41bf0c7"
|
resolved "https://codeload.github.com/anthonydresser/service-downloader/tar.gz/6ebb0465573cc140e461a22f334260f55ef45546"
|
||||||
dependencies:
|
dependencies:
|
||||||
decompress "^4.2.0"
|
decompress "^4.2.0"
|
||||||
eventemitter2 "^5.0.1"
|
eventemitter2 "^5.0.1"
|
||||||
http-proxy-agent "^2.0.0"
|
http-proxy-agent "^2.1.0"
|
||||||
https-proxy-agent "^2.1.1"
|
https-proxy-agent "^2.2.1"
|
||||||
mkdirp "^0.5.1"
|
mkdirp "^0.5.1"
|
||||||
tmp "^0.0.33"
|
tmp "^0.0.33"
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.8",
|
"dataprotocol-client": "github:Microsoft/sqlops-dataprotocolclient#0.2.8",
|
||||||
"opener": "^1.4.3",
|
"opener": "^1.4.3",
|
||||||
"service-downloader": "github:anthonydresser/service-downloader#0.1.4",
|
"service-downloader": "github:anthonydresser/service-downloader#0.1.5",
|
||||||
"vscode-extension-telemetry": "^0.0.15"
|
"vscode-extension-telemetry": "^0.0.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
||||||
"version": "1.5.0-alpha.28",
|
"version": "1.5.0-alpha.34",
|
||||||
"downloadFileNames": {
|
"downloadFileNames": {
|
||||||
"Windows_86": "win-x86-netcoreapp2.1.zip",
|
"Windows_86": "win-x86-netcoreapp2.1.zip",
|
||||||
"Windows_64": "win-x64-netcoreapp2.1.zip",
|
"Windows_64": "win-x64-netcoreapp2.1.zip",
|
||||||
|
|||||||
@@ -191,14 +191,14 @@ graceful-fs@^4.1.10:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
|
||||||
|
|
||||||
http-proxy-agent@^2.0.0:
|
http-proxy-agent@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
|
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base "4"
|
agent-base "4"
|
||||||
debug "3.1.0"
|
debug "3.1.0"
|
||||||
|
|
||||||
https-proxy-agent@^2.1.1:
|
https-proxy-agent@^2.2.1:
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
|
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -315,14 +315,14 @@ semver@^5.3.0:
|
|||||||
version "5.5.0"
|
version "5.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
|
||||||
|
|
||||||
"service-downloader@github:anthonydresser/service-downloader#0.1.4":
|
"service-downloader@github:anthonydresser/service-downloader#0.1.5":
|
||||||
version "0.1.4"
|
version "0.1.5"
|
||||||
resolved "https://codeload.github.com/anthonydresser/service-downloader/tar.gz/3c0abdf8603aca85d2eacfac3c547173e41bf0c7"
|
resolved "https://codeload.github.com/anthonydresser/service-downloader/tar.gz/6ebb0465573cc140e461a22f334260f55ef45546"
|
||||||
dependencies:
|
dependencies:
|
||||||
decompress "^4.2.0"
|
decompress "^4.2.0"
|
||||||
eventemitter2 "^5.0.1"
|
eventemitter2 "^5.0.1"
|
||||||
http-proxy-agent "^2.0.0"
|
http-proxy-agent "^2.1.0"
|
||||||
https-proxy-agent "^2.1.1"
|
https-proxy-agent "^2.2.1"
|
||||||
mkdirp "^0.5.1"
|
mkdirp "^0.5.1"
|
||||||
tmp "^0.0.33"
|
tmp "^0.0.33"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sqlops",
|
"name": "sqlops",
|
||||||
"version": "0.33.2",
|
"version": "0.33.7",
|
||||||
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
|
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Microsoft Corporation"
|
"name": "Microsoft Corporation"
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
"reflect-metadata": "^0.1.8",
|
"reflect-metadata": "^0.1.8",
|
||||||
"rxjs": "5.4.0",
|
"rxjs": "5.4.0",
|
||||||
"semver": "^5.5.0",
|
"semver": "^5.5.0",
|
||||||
"slickgrid": "github:anthonydresser/SlickGrid#2.3.25",
|
"slickgrid": "github:anthonydresser/SlickGrid#2.3.27",
|
||||||
"spdlog": "0.7.1",
|
"spdlog": "0.7.1",
|
||||||
"sudo-prompt": "8.2.0",
|
"sudo-prompt": "8.2.0",
|
||||||
"svg.js": "^2.2.5",
|
"svg.js": "^2.2.5",
|
||||||
@@ -167,5 +167,8 @@
|
|||||||
"windows-foreground-love": "0.1.0",
|
"windows-foreground-love": "0.1.0",
|
||||||
"windows-mutex": "^0.2.0",
|
"windows-mutex": "^0.2.0",
|
||||||
"windows-process-tree": "0.2.2"
|
"windows-process-tree": "0.2.2"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"rc": "1.2.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2791
samples/extensionSamples/package-lock.json
generated
2791
samples/extensionSamples/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
2642
samples/serverReports/package-lock.json
generated
2642
samples/serverReports/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
2794
samples/sp_whoIsActive/package-lock.json
generated
2794
samples/sp_whoIsActive/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
2687
samples/sqlservices/package-lock.json
generated
2687
samples/sqlservices/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -518,7 +518,8 @@ export default class MainController implements vscode.Disposable {
|
|||||||
let runButton = view.modelBuilder.button()
|
let runButton = view.modelBuilder.button()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
label: 'Run',
|
label: 'Run',
|
||||||
iconPath: runIcon
|
iconPath: runIcon,
|
||||||
|
title: 'Run title'
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
let monitorLightPath = vscode.Uri.file(path.join(__dirname, '..', 'media', 'monitor.svg'));
|
let monitorLightPath = vscode.Uri.file(path.join(__dirname, '..', 'media', 'monitor.svg'));
|
||||||
@@ -530,7 +531,8 @@ export default class MainController implements vscode.Disposable {
|
|||||||
let monitorButton = view.modelBuilder.button()
|
let monitorButton = view.modelBuilder.button()
|
||||||
.withProperties({
|
.withProperties({
|
||||||
label: 'Monitor',
|
label: 'Monitor',
|
||||||
iconPath: monitorIcon
|
iconPath: monitorIcon,
|
||||||
|
title: 'Monitor title'
|
||||||
}).component();
|
}).component();
|
||||||
let toolbarModel = view.modelBuilder.toolbarContainer()
|
let toolbarModel = view.modelBuilder.toolbarContainer()
|
||||||
.withToolbarItems([{
|
.withToolbarItems([{
|
||||||
|
|||||||
@@ -23,6 +23,18 @@ export class Button extends vsButton {
|
|||||||
this.$el.style('outline-color', this.buttonFocusOutline ? this.buttonFocusOutline.toString() : null);
|
this.$el.style('outline-color', this.buttonFocusOutline ? this.buttonFocusOutline.toString() : null);
|
||||||
this.$el.style('outline-width', '1px');
|
this.$el.style('outline-width', '1px');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.$el.on(DOM.EventType.MOUSE_DOWN, (e) => {
|
||||||
|
const mouseEvent = e as MouseEvent;
|
||||||
|
if (!this.$el.hasClass('disabled') && mouseEvent.button === 0) {
|
||||||
|
this.$el.addClass('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$el.on([DOM.EventType.MOUSE_UP], (e) => {
|
||||||
|
DOM.EventHelper.stop(e);
|
||||||
|
this.$el.removeClass('active');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public style(styles: IButtonStyles): void {
|
public style(styles: IButtonStyles): void {
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ export abstract class Modal extends Disposable implements IThemable {
|
|||||||
if (this._modalOptions.isAngular === false && this._modalOptions.hasErrors) {
|
if (this._modalOptions.isAngular === false && this._modalOptions.hasErrors) {
|
||||||
let builder = errorMessagesInFooter ? this._leftFooter : body;
|
let builder = errorMessagesInFooter ? this._leftFooter : body;
|
||||||
builder.div({ class: 'dialogErrorMessage', id: 'dialogErrorMessage' }, (errorMessageContainer) => {
|
builder.div({ class: 'dialogErrorMessage', id: 'dialogErrorMessage' }, (errorMessageContainer) => {
|
||||||
errorMessageContainer.div({ class: 'icon error' }, (iconContainer) => {
|
errorMessageContainer.div({ class: 'sql icon error' }, (iconContainer) => {
|
||||||
this._errorIconElement = iconContainer.getHTMLElement();
|
this._errorIconElement = iconContainer.getHTMLElement();
|
||||||
this._errorIconElement.style.visibility = 'hidden';
|
this._errorIconElement.style.visibility = 'hidden';
|
||||||
});
|
});
|
||||||
@@ -518,5 +518,6 @@ export abstract class Modal extends Disposable implements IThemable {
|
|||||||
public dispose() {
|
public dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
this._keydownListener.dispose();
|
this._keydownListener.dispose();
|
||||||
|
this._footerButtons = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ export class TabbedPanel extends Disposable implements IThemable {
|
|||||||
private _onTabChange = new Emitter<PanelTabIdentifier>();
|
private _onTabChange = new Emitter<PanelTabIdentifier>();
|
||||||
public onTabChange: Event<PanelTabIdentifier> = this._onTabChange.event;
|
public onTabChange: Event<PanelTabIdentifier> = this._onTabChange.event;
|
||||||
|
|
||||||
|
private tabHistory: string[] = [];
|
||||||
|
|
||||||
constructor(private container: HTMLElement, private options: IPanelOptions = defaultOptions) {
|
constructor(private container: HTMLElement, private options: IPanelOptions = defaultOptions) {
|
||||||
super();
|
super();
|
||||||
this.$parent = this._register($('.tabbedPanel'));
|
this.$parent = this._register($('.tabbedPanel'));
|
||||||
@@ -152,6 +154,7 @@ export class TabbedPanel extends Disposable implements IThemable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._shownTab = id;
|
this._shownTab = id;
|
||||||
|
this.tabHistory.push(id);
|
||||||
this.$body.clearChildren();
|
this.$body.clearChildren();
|
||||||
let tab = this._tabMap.get(this._shownTab);
|
let tab = this._tabMap.get(this._shownTab);
|
||||||
this.$body.attr('aria-labelledby', tab.identifier);
|
this.$body.attr('aria-labelledby', tab.identifier);
|
||||||
@@ -173,6 +176,26 @@ export class TabbedPanel extends Disposable implements IThemable {
|
|||||||
}
|
}
|
||||||
this._tabMap.get(tab).header.destroy();
|
this._tabMap.get(tab).header.destroy();
|
||||||
this._tabMap.delete(tab);
|
this._tabMap.delete(tab);
|
||||||
|
if (this._shownTab === tab) {
|
||||||
|
this._shownTab = undefined;
|
||||||
|
while (this._shownTab === undefined && this.tabHistory.length > 0) {
|
||||||
|
let lastTab = this.tabHistory.shift();
|
||||||
|
if (this._tabMap.get(lastTab)) {
|
||||||
|
this.showTab(lastTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this shouldn't happen but just in case
|
||||||
|
if (this._shownTab === undefined && this._tabMap.size > 0) {
|
||||||
|
this.showTab(this._tabMap.keys().next().value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.options.showHeaderWhenSingleView && this._tabMap.size === 1 && this._headerVisible) {
|
||||||
|
this.$header.offDOM();
|
||||||
|
this._headerVisible = false;
|
||||||
|
this.layout(this._currentDimensions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public style(styles: IPanelStyles): void {
|
public style(styles: IPanelStyles): void {
|
||||||
@@ -180,14 +203,16 @@ export class TabbedPanel extends Disposable implements IThemable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public layout(dimension: Dimension): void {
|
public layout(dimension: Dimension): void {
|
||||||
this._currentDimensions = dimension;
|
if (dimension) {
|
||||||
this.$parent.style('height', dimension.height + 'px');
|
this._currentDimensions = dimension;
|
||||||
this.$parent.style('width', dimension.width + 'px');
|
this.$parent.style('height', dimension.height + 'px');
|
||||||
this.$header.style('width', dimension.width + 'px');
|
this.$parent.style('width', dimension.width + 'px');
|
||||||
this.$body.style('width', dimension.width + 'px');
|
this.$header.style('width', dimension.width + 'px');
|
||||||
const bodyHeight = dimension.height - (this._headerVisible ? this.headersize : 0);
|
this.$body.style('width', dimension.width + 'px');
|
||||||
this.$body.style('height', bodyHeight + 'px');
|
const bodyHeight = dimension.height - (this._headerVisible ? this.headersize : 0);
|
||||||
this._layoutCurrentTab(new Dimension(dimension.width, bodyHeight));
|
this.$body.style('height', bodyHeight + 'px');
|
||||||
|
this._layoutCurrentTab(new Dimension(dimension.width, bodyHeight));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _layoutCurrentTab(dimension: Dimension): void {
|
private _layoutCurrentTab(dimension: Dimension): void {
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ export interface IView extends HeightIView {
|
|||||||
readonly onDidChange: Event<number | undefined>;
|
readonly onDidChange: Event<number | undefined>;
|
||||||
render(container: HTMLElement, orientation: Orientation): void;
|
render(container: HTMLElement, orientation: Orientation): void;
|
||||||
layout(size: number, orientation: Orientation): void;
|
layout(size: number, orientation: Orientation): void;
|
||||||
|
onAdd?(): void;
|
||||||
|
onRemove?(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ISashEvent {
|
interface ISashEvent {
|
||||||
@@ -48,6 +50,8 @@ interface IViewItem extends HeightIViewItem {
|
|||||||
container: HTMLElement;
|
container: HTMLElement;
|
||||||
disposable: IDisposable;
|
disposable: IDisposable;
|
||||||
layout(): void;
|
layout(): void;
|
||||||
|
onRemove: () => void;
|
||||||
|
onAdd: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ISashItem {
|
interface ISashItem {
|
||||||
@@ -109,6 +113,9 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
|||||||
private _onDidSashReset = new Emitter<void>();
|
private _onDidSashReset = new Emitter<void>();
|
||||||
readonly onDidSashReset = this._onDidSashReset.event;
|
readonly onDidSashReset = this._onDidSashReset.event;
|
||||||
|
|
||||||
|
private _onScroll = new Emitter<number>();
|
||||||
|
readonly onScroll = this._onScroll.event;
|
||||||
|
|
||||||
get length(): number {
|
get length(): number {
|
||||||
return this.viewItems.length;
|
return this.viewItems.length;
|
||||||
}
|
}
|
||||||
@@ -124,6 +131,7 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
|||||||
debounceEvent(this.scrollable.onScroll, (l, e) => e, 25)(e => {
|
debounceEvent(this.scrollable.onScroll, (l, e) => e, 25)(e => {
|
||||||
this.render(e.scrollTop, e.height);
|
this.render(e.scrollTop, e.height);
|
||||||
this.relayout();
|
this.relayout();
|
||||||
|
this._onScroll.fire(e.scrollTop);
|
||||||
});
|
});
|
||||||
let domNode = this.scrollable.getDomNode();
|
let domNode = this.scrollable.getDomNode();
|
||||||
dom.addClass(this.el, 'monaco-scroll-split-view');
|
dom.addClass(this.el, 'monaco-scroll-split-view');
|
||||||
@@ -155,6 +163,9 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
|||||||
});
|
});
|
||||||
const disposable = combinedDisposable([onChangeDisposable, containerDisposable]);
|
const disposable = combinedDisposable([onChangeDisposable, containerDisposable]);
|
||||||
|
|
||||||
|
const onAdd = view.onAdd ? () => view.onAdd() : () => { };
|
||||||
|
const onRemove = view.onRemove ? () => view.onRemove() : () => { };
|
||||||
|
|
||||||
const layoutContainer = this.orientation === Orientation.VERTICAL
|
const layoutContainer = this.orientation === Orientation.VERTICAL
|
||||||
? size => item.container.style.height = `${item.size}px`
|
? size => item.container.style.height = `${item.size}px`
|
||||||
: size => item.container.style.width = `${item.size}px`;
|
: size => item.container.style.width = `${item.size}px`;
|
||||||
@@ -165,7 +176,7 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
|||||||
};
|
};
|
||||||
|
|
||||||
size = Math.round(size);
|
size = Math.round(size);
|
||||||
const item: IViewItem = { view, container, size, layout, disposable, height: size, top: 0, width: 0 };
|
const item: IViewItem = { onRemove, onAdd, view, container, size, layout, disposable, height: size, top: 0, width: 0 };
|
||||||
this.viewItems.splice(viewIndex, 0, item);
|
this.viewItems.splice(viewIndex, 0, item);
|
||||||
|
|
||||||
this.onInsertItems(new ArrayIterator([item]), viewIndex > 0 ? this.viewItems[viewIndex - 1].view.id : undefined);
|
this.onInsertItems(new ArrayIterator([item]), viewIndex > 0 ? this.viewItems[viewIndex - 1].view.id : undefined);
|
||||||
@@ -220,6 +231,9 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
|||||||
});
|
});
|
||||||
const disposable = combinedDisposable([onChangeDisposable, containerDisposable]);
|
const disposable = combinedDisposable([onChangeDisposable, containerDisposable]);
|
||||||
|
|
||||||
|
const onAdd = view.onAdd ? () => view.onAdd() : () => { };
|
||||||
|
const onRemove = view.onRemove ? () => view.onRemove() : () => { };
|
||||||
|
|
||||||
const layoutContainer = this.orientation === Orientation.VERTICAL
|
const layoutContainer = this.orientation === Orientation.VERTICAL
|
||||||
? size => item.container.style.height = `${item.size}px`
|
? size => item.container.style.height = `${item.size}px`
|
||||||
: size => item.container.style.width = `${item.size}px`;
|
: size => item.container.style.width = `${item.size}px`;
|
||||||
@@ -230,7 +244,7 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
|||||||
};
|
};
|
||||||
|
|
||||||
size = Math.round(size);
|
size = Math.round(size);
|
||||||
const item: IViewItem = { view, container, size, layout, disposable, height: size, top: 0, width: 0 };
|
const item: IViewItem = { onAdd, onRemove, view, container, size, layout, disposable, height: size, top: 0, width: 0 };
|
||||||
this.viewItems.splice(index, 0, item);
|
this.viewItems.splice(index, 0, item);
|
||||||
|
|
||||||
this.onInsertItems(new ArrayIterator([item]), index > 0 ? this.viewItems[index - 1].view.id : undefined);
|
this.onInsertItems(new ArrayIterator([item]), index > 0 ? this.viewItems[index - 1].view.id : undefined);
|
||||||
@@ -330,9 +344,16 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
|||||||
this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndex);
|
this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setScrollPosition(position: number) {
|
||||||
|
this.scrollable.setScrollPosition({ scrollTop: position });
|
||||||
|
}
|
||||||
|
|
||||||
layout(size: number): void {
|
layout(size: number): void {
|
||||||
const previousSize = Math.max(this.size, this.contentSize);
|
const previousSize = this.size;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
|
this.contentSize = 0;
|
||||||
|
this.lastRenderHeight = undefined;
|
||||||
|
this.lastRenderTop = undefined;
|
||||||
this.resize(this.viewItems.length - 1, size - previousSize);
|
this.resize(this.viewItems.length - 1, size - previousSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,6 +505,8 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
item.layout();
|
item.layout();
|
||||||
|
|
||||||
|
item.onAdd();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,6 +516,8 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.el.removeChild(item.container);
|
this.el.removeChild(item.container);
|
||||||
|
|
||||||
|
item.onRemove();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||||
|
import { range } from 'vs/base/common/arrays';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the various additional navigation keybindings we want out of slickgrid
|
* Implements the various additional navigation keybindings we want out of slickgrid
|
||||||
@@ -50,6 +51,14 @@ export class AdditionalKeyBindings<T> implements Slick.Plugin<T> {
|
|||||||
}
|
}
|
||||||
} else if (event.equals(KeyCode.End | KeyMod.CtrlCmd)) {
|
} else if (event.equals(KeyCode.End | KeyMod.CtrlCmd)) {
|
||||||
this.grid.setActiveCell(this.grid.getDataLength() - 1, this.grid.getColumns().length - 1);
|
this.grid.setActiveCell(this.grid.getDataLength() - 1, this.grid.getColumns().length - 1);
|
||||||
|
} else if (event.equals(KeyCode.KEY_A | KeyMod.CtrlCmd)) {
|
||||||
|
// check if we can set the rows directly on the selectionModel, its cleaner
|
||||||
|
let selectionModel = this.grid.getSelectionModel();
|
||||||
|
if (selectionModel) {
|
||||||
|
selectionModel.setSelectedRanges([new Slick.Range(0, 0, this.grid.getDataLength() - 1, this.grid.getColumns().length - 1)]);
|
||||||
|
} else {
|
||||||
|
this.grid.setSelectedRows(range(this.grid.getDataLength()));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
handled = false;
|
handled = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { mixin } from 'vs/base/common/objects';
|
import { mixin } from 'vs/base/common/objects';
|
||||||
|
|
||||||
require.__$__nodeRequire('slickgrid/plugins/slick.cellrangedecorator');
|
|
||||||
|
|
||||||
const defaultOptions: ICellRangeSelectorOptions = {
|
const defaultOptions: ICellRangeSelectorOptions = {
|
||||||
selectionCss: {
|
selectionCss: {
|
||||||
'border': '2px dashed blue'
|
'border': '2px dashed blue'
|
||||||
@@ -44,6 +42,8 @@ export class CellRangeSelector<T> implements ICellRangeSelector<T> {
|
|||||||
public onCellRangeSelected = new Slick.Event<{ range: Slick.Range }>();
|
public onCellRangeSelected = new Slick.Event<{ range: Slick.Range }>();
|
||||||
|
|
||||||
constructor(private options: ICellRangeSelectorOptions) {
|
constructor(private options: ICellRangeSelectorOptions) {
|
||||||
|
require.__$__nodeRequire('slickgrid/plugins/slick.cellrangedecorator');
|
||||||
|
|
||||||
this.options = mixin(this.options, defaultOptions, false);
|
this.options = mixin(this.options, defaultOptions, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ export class CellRangeSelector<T> implements ICellRangeSelector<T> {
|
|||||||
|
|
||||||
this.canvas.classList.add(this.options.dragClass);
|
this.canvas.classList.add(this.options.dragClass);
|
||||||
|
|
||||||
this.grid.focus();
|
this.grid.setActiveCell(cell.row, cell.cell);
|
||||||
|
|
||||||
let start = this.grid.getCellFromPoint(
|
let start = this.grid.getCellFromPoint(
|
||||||
dd.startX - $(this.canvas).offset().left,
|
dd.startX - $(this.canvas).offset().left,
|
||||||
@@ -128,8 +128,11 @@ export class CellRangeSelector<T> implements ICellRangeSelector<T> {
|
|||||||
this.canvas.classList.remove(this.options.dragClass);
|
this.canvas.classList.remove(this.options.dragClass);
|
||||||
this.dragging = false;
|
this.dragging = false;
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
|
|
||||||
this.decorator.hide();
|
this.decorator.hide();
|
||||||
|
// if this happens to fast there is a chance we don't have the necessary information to actually do proper selection
|
||||||
|
if (!dd || !dd.range || !dd.range.start || !dd.range.end) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.onCellRangeSelected.notify({
|
this.onCellRangeSelected.notify({
|
||||||
range: new Slick.Range(
|
range: new Slick.Range(
|
||||||
dd.range.start.row,
|
dd.range.start.row,
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import { isUndefinedOrNull } from 'vs/base/common/types';
|
|||||||
|
|
||||||
import { CellRangeSelector, ICellRangeSelector } from 'sql/base/browser/ui/table/plugins/cellRangeSelector';
|
import { CellRangeSelector, ICellRangeSelector } from 'sql/base/browser/ui/table/plugins/cellRangeSelector';
|
||||||
|
|
||||||
require.__$__nodeRequire('slickgrid/plugins/slick.cellrangedecorator');
|
|
||||||
|
|
||||||
export interface ICellSelectionModelOptions {
|
export interface ICellSelectionModelOptions {
|
||||||
cellRangeSelector?: any;
|
cellRangeSelector?: any;
|
||||||
selectActiveCell?: boolean;
|
selectActiveCell?: boolean;
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ export class CopyKeybind<T> implements Slick.Plugin<T> {
|
|||||||
let selectionModel = this.grid.getSelectionModel();
|
let selectionModel = this.grid.getSelectionModel();
|
||||||
let ranges: Slick.Range[];
|
let ranges: Slick.Range[];
|
||||||
// check to see if we can get the range from the model directly
|
// check to see if we can get the range from the model directly
|
||||||
if (selectionModel && (<any>selectionModel).getSelectedRanges) {
|
if (selectionModel) {
|
||||||
ranges = (<any>selectionModel).getSelectedRanges();
|
ranges = selectionModel.getSelectedRanges();
|
||||||
} else {
|
} else {
|
||||||
let selectedRows = this.grid.getSelectedRows();
|
let selectedRows = this.grid.getSelectedRows();
|
||||||
let startColumn = 0;
|
let startColumn = 0;
|
||||||
|
|||||||
@@ -36,23 +36,31 @@ export class RowNumberColumn<T> implements Slick.Plugin<T> {
|
|||||||
private handleClick(e: MouseEvent, args: Slick.OnClickEventArgs<T>): void {
|
private handleClick(e: MouseEvent, args: Slick.OnClickEventArgs<T>): void {
|
||||||
if (this.grid.getColumns()[args.cell].id === 'rowNumber') {
|
if (this.grid.getColumns()[args.cell].id === 'rowNumber') {
|
||||||
this.grid.setActiveCell(args.row, 1);
|
this.grid.setActiveCell(args.row, 1);
|
||||||
this.grid.setSelectedRows([args.row]);
|
if (this.grid.getSelectionModel()) {
|
||||||
|
this.grid.setSelectedRows([args.row]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleHeaderClick(e: MouseEvent, args: Slick.OnHeaderClickEventArgs<T>): void {
|
private handleHeaderClick(e: MouseEvent, args: Slick.OnHeaderClickEventArgs<T>): void {
|
||||||
if (args.column.id === 'rowNumber') {
|
if (args.column.id === 'rowNumber') {
|
||||||
this.grid.setActiveCell(0, 1);
|
this.grid.setActiveCell(0, 1);
|
||||||
this.grid.setSelectedRows(range(this.grid.getDataLength()));
|
if (this.grid.getSelectionModel()) {
|
||||||
|
this.grid.setSelectedRows(range(this.grid.getDataLength()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getColumnDefinition(): Slick.Column<T> {
|
public getColumnDefinition(): Slick.Column<T> {
|
||||||
|
// that smallest we can make it is 22 due to padding and margins in the cells
|
||||||
|
let columnWidth = Math.max(this.options.numberOfRows.toString().length * sizePerDigit, 22);
|
||||||
return {
|
return {
|
||||||
id: 'rowNumber',
|
id: 'rowNumber',
|
||||||
name: '',
|
name: '',
|
||||||
field: 'rowNumber',
|
field: 'rowNumber',
|
||||||
width: this.options.numberOfRows.toString().length * sizePerDigit,
|
width: columnWidth,
|
||||||
|
minWidth: columnWidth,
|
||||||
|
maxWidth: columnWidth,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
cssClass: this.options.cssClass,
|
cssClass: this.options.cssClass,
|
||||||
focusable: false,
|
focusable: false,
|
||||||
|
|||||||
@@ -166,6 +166,10 @@ export class Table<T extends Slick.SlickData> extends Widget implements IThemabl
|
|||||||
this._grid.setData(this._data, true);
|
this._grid.setData(this._data, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getData(): Slick.DataProvider<T> {
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
|
||||||
get columns(): Slick.Column<T>[] {
|
get columns(): Slick.Column<T>[] {
|
||||||
return this._grid.getColumns();
|
return this._grid.getColumns();
|
||||||
}
|
}
|
||||||
@@ -244,7 +248,6 @@ export class Table<T extends Slick.SlickData> extends Widget implements IThemabl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.resizeCanvas();
|
this.resizeCanvas();
|
||||||
this.autosizeColumns();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
autosizeColumns() {
|
autosizeColumns() {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of vs/base/common/event/echo that is clearable
|
* Implementation of vs/base/common/event/echo that is clearable
|
||||||
@@ -37,3 +38,52 @@ export function echo<T>(event: Event<T>, nextTick = false, buffer: T[] = []): {
|
|||||||
clear
|
clear
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of vs/base/common/event/debounceEvent that is clearable
|
||||||
|
*/
|
||||||
|
export function debounceEvent<T>(event: Event<T>, merger: (last: T, event: T) => T, delay?: number, leading?: boolean): { clear: () => void; event: Event<T> };
|
||||||
|
export function debounceEvent<I, O>(event: Event<I>, merger: (last: O, event: I) => O, delay?: number, leading?: boolean): { clear: () => void; event: Event<O> };
|
||||||
|
export function debounceEvent<I, O>(event: Event<I>, merger: (last: O, event: I) => O, delay: number = 100, leading = false): { clear: () => void; event: Event<O> } {
|
||||||
|
|
||||||
|
let subscription: IDisposable;
|
||||||
|
let output: O = undefined;
|
||||||
|
let handle: any = undefined;
|
||||||
|
let numDebouncedCalls = 0;
|
||||||
|
|
||||||
|
const clear = () => output = undefined;
|
||||||
|
|
||||||
|
const emitter = new Emitter<O>({
|
||||||
|
onFirstListenerAdd() {
|
||||||
|
subscription = event(cur => {
|
||||||
|
numDebouncedCalls++;
|
||||||
|
output = merger(output, cur);
|
||||||
|
|
||||||
|
if (leading && !handle) {
|
||||||
|
emitter.fire(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeout(handle);
|
||||||
|
handle = setTimeout(() => {
|
||||||
|
let _output = output;
|
||||||
|
output = undefined;
|
||||||
|
handle = undefined;
|
||||||
|
if (!leading || numDebouncedCalls > 1) {
|
||||||
|
emitter.fire(_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
numDebouncedCalls = 0;
|
||||||
|
}, delay);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onLastListenerRemove() {
|
||||||
|
subscription.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
event: emitter.event,
|
||||||
|
clear
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,21 +63,21 @@
|
|||||||
background: url("globalerror.svg") center center no-repeat;
|
background: url("globalerror.svg") center center no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vs .icon.error,
|
.vs .sql.icon.error,
|
||||||
.vs-dark .icon.error,
|
.vs-dark .sql.icon.error,
|
||||||
.hc-black .icon.error {
|
.hc-black .sql.icon.error {
|
||||||
content: url("status_error.svg");
|
content: url("status_error.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
.vs .icon.warning,
|
.vs .sql.icon.warning,
|
||||||
.vs-dark .icon.warning,
|
.vs-dark .sql.icon.warning,
|
||||||
.hc-black .icon.warning {
|
.hc-black .sql.icon.warning {
|
||||||
content: url("status_warning.svg");
|
content: url("status_warning.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
.vs .icon.info,
|
.vs .sql.icon.info,
|
||||||
.vs-dark .icon.info,
|
.vs-dark .sql.icon.info,
|
||||||
.hc-black .icon.info {
|
.hc-black .sql.icon.info {
|
||||||
content: url("status_info.svg");
|
content: url("status_info.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ export class AccountPicker extends Disposable {
|
|||||||
|
|
||||||
// Create refresh account action
|
// Create refresh account action
|
||||||
this._refreshContainer = DOM.append(this._rootElement, DOM.$('div.refresh-container'));
|
this._refreshContainer = DOM.append(this._rootElement, DOM.$('div.refresh-container'));
|
||||||
DOM.append(this._refreshContainer, DOM.$('div.icon warning'));
|
DOM.append(this._refreshContainer, DOM.$('div.sql icon warning'));
|
||||||
let actionBar = new ActionBar(this._refreshContainer, { animated: false });
|
let actionBar = new ActionBar(this._refreshContainer, { animated: false });
|
||||||
this._refreshAccountAction = this._instantiationService.createInstance(RefreshAccountAction);
|
this._refreshAccountAction = this._instantiationService.createInstance(RefreshAccountAction);
|
||||||
actionBar.push(this._refreshAccountAction, { icon: false, label: true });
|
actionBar.push(this._refreshAccountAction, { icon: false, label: true });
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ export class ConnectionStore {
|
|||||||
.then(savedCred => {
|
.then(savedCred => {
|
||||||
if (savedCred) {
|
if (savedCred) {
|
||||||
credentialsItem.password = savedCred.password;
|
credentialsItem.password = savedCred.password;
|
||||||
|
credentialsItem.options['password'] = savedCred.password;
|
||||||
}
|
}
|
||||||
resolve({ profile: credentialsItem, savedCred: !!savedCred });
|
resolve({ profile: credentialsItem, savedCred: !!savedCred });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -156,11 +156,6 @@ export class ConnectionWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fillInConnectionForm(): void {
|
private fillInConnectionForm(): void {
|
||||||
// Connection name
|
|
||||||
let connectionNameOption = this._optionsMaps[ConnectionOptionSpecialType.connectionName];
|
|
||||||
let connectionNameBuilder = DialogHelper.appendRow(this._tableContainer, connectionNameOption.displayName, 'connection-label', 'connection-input');
|
|
||||||
this._connectionNameInputBox = new InputBox(connectionNameBuilder.getHTMLElement(), this._contextViewService, { ariaLabel: connectionNameOption.displayName });
|
|
||||||
|
|
||||||
// Server name
|
// Server name
|
||||||
let serverNameOption = this._optionsMaps[ConnectionOptionSpecialType.serverName];
|
let serverNameOption = this._optionsMaps[ConnectionOptionSpecialType.serverName];
|
||||||
let serverNameBuilder = DialogHelper.appendRow(this._tableContainer, serverNameOption.displayName, 'connection-label', 'connection-input');
|
let serverNameBuilder = DialogHelper.appendRow(this._tableContainer, serverNameOption.displayName, 'connection-label', 'connection-input');
|
||||||
@@ -222,6 +217,11 @@ export class ConnectionWidget {
|
|||||||
let serverGroupBuilder = DialogHelper.appendRow(this._tableContainer, this._serverGroupDisplayString, 'connection-label', 'connection-input');
|
let serverGroupBuilder = DialogHelper.appendRow(this._tableContainer, this._serverGroupDisplayString, 'connection-label', 'connection-input');
|
||||||
DialogHelper.appendInputSelectBox(serverGroupBuilder, this._serverGroupSelectBox);
|
DialogHelper.appendInputSelectBox(serverGroupBuilder, this._serverGroupSelectBox);
|
||||||
|
|
||||||
|
// Connection name
|
||||||
|
let connectionNameOption = this._optionsMaps[ConnectionOptionSpecialType.connectionName];
|
||||||
|
let connectionNameBuilder = DialogHelper.appendRow(this._tableContainer, connectionNameOption.displayName, 'connection-label', 'connection-input');
|
||||||
|
this._connectionNameInputBox = new InputBox(connectionNameBuilder.getHTMLElement(), this._contextViewService, { ariaLabel: connectionNameOption.displayName });
|
||||||
|
|
||||||
let AdvancedLabel = localize('advanced', 'Advanced...');
|
let AdvancedLabel = localize('advanced', 'Advanced...');
|
||||||
this._advancedButton = this.createAdvancedButton(this._tableContainer, AdvancedLabel);
|
this._advancedButton = this.createAdvancedButton(this._tableContainer, AdvancedLabel);
|
||||||
}
|
}
|
||||||
@@ -398,7 +398,7 @@ export class ConnectionWidget {
|
|||||||
|
|
||||||
public focusOnOpen(): void {
|
public focusOnOpen(): void {
|
||||||
this._handleClipboard();
|
this._handleClipboard();
|
||||||
this._connectionNameInputBox.focus();
|
this._serverNameInputBox.focus();
|
||||||
this.focusPasswordIfNeeded();
|
this.focusPasswordIfNeeded();
|
||||||
this.clearValidationMessages();
|
this.clearValidationMessages();
|
||||||
}
|
}
|
||||||
@@ -492,6 +492,7 @@ export class ConnectionWidget {
|
|||||||
this._databaseNameInputBox.enabled = false;
|
this._databaseNameInputBox.enabled = false;
|
||||||
this._userNameInputBox.disable();
|
this._userNameInputBox.disable();
|
||||||
this._passwordInputBox.disable();
|
this._passwordInputBox.disable();
|
||||||
|
this._connectionNameInputBox.disable();
|
||||||
this._rememberPasswordCheckBox.enabled = false;
|
this._rememberPasswordCheckBox.enabled = false;
|
||||||
if (this._authTypeSelectBox) {
|
if (this._authTypeSelectBox) {
|
||||||
this._authTypeSelectBox.disable();
|
this._authTypeSelectBox.disable();
|
||||||
@@ -503,6 +504,7 @@ export class ConnectionWidget {
|
|||||||
|
|
||||||
this._serverGroupSelectBox.enable();
|
this._serverGroupSelectBox.enable();
|
||||||
this._serverNameInputBox.enable();
|
this._serverNameInputBox.enable();
|
||||||
|
this._connectionNameInputBox.enable();
|
||||||
this._databaseNameInputBox.enabled = true;
|
this._databaseNameInputBox.enabled = true;
|
||||||
let currentAuthType: AuthenticationType = undefined;
|
let currentAuthType: AuthenticationType = undefined;
|
||||||
if (this._authTypeSelectBox) {
|
if (this._authTypeSelectBox) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import * as TelemetryUtils from 'sql/common/telemetryUtilities';
|
|||||||
import { IInsightsView, IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
import { IInsightsView, IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
||||||
import { memoize, unmemoize } from 'sql/base/common/decorators';
|
import { memoize, unmemoize } from 'sql/base/common/decorators';
|
||||||
import { mixin } from 'sql/base/common/objects';
|
import { mixin } from 'sql/base/common/objects';
|
||||||
|
import { LegendPosition, DataDirection, ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
|
|
||||||
import * as colors from 'vs/platform/theme/common/colorRegistry';
|
import * as colors from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
@@ -21,29 +22,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
|||||||
|
|
||||||
declare var Chart: any;
|
declare var Chart: any;
|
||||||
|
|
||||||
export enum ChartType {
|
|
||||||
Bar = 'bar',
|
|
||||||
Doughnut = 'doughnut',
|
|
||||||
HorizontalBar = 'horizontalBar',
|
|
||||||
Line = 'line',
|
|
||||||
Pie = 'pie',
|
|
||||||
TimeSeries = 'timeSeries',
|
|
||||||
Scatter = 'scatter'
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum DataDirection {
|
|
||||||
Vertical = 'vertical',
|
|
||||||
Horizontal = 'horizontal'
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum LegendPosition {
|
|
||||||
Top = 'top',
|
|
||||||
Bottom = 'bottom',
|
|
||||||
Left = 'left',
|
|
||||||
Right = 'right',
|
|
||||||
None = 'none'
|
|
||||||
}
|
|
||||||
|
|
||||||
export function customMixin(destination: any, source: any, overwrite?: boolean): any {
|
export function customMixin(destination: any, source: any, overwrite?: boolean): any {
|
||||||
if (types.isObject(source)) {
|
if (types.isObject(source)) {
|
||||||
mixin(destination, source, overwrite, customMixin);
|
mixin(destination, source, overwrite, customMixin);
|
||||||
|
|||||||
@@ -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.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
export enum ChartType {
|
||||||
|
Bar = 'bar',
|
||||||
|
Doughnut = 'doughnut',
|
||||||
|
HorizontalBar = 'horizontalBar',
|
||||||
|
Line = 'line',
|
||||||
|
Pie = 'pie',
|
||||||
|
TimeSeries = 'timeSeries',
|
||||||
|
Scatter = 'scatter'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DataDirection {
|
||||||
|
Vertical = 'vertical',
|
||||||
|
Horizontal = 'horizontal'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum LegendPosition {
|
||||||
|
Top = 'top',
|
||||||
|
Bottom = 'bottom',
|
||||||
|
Left = 'left',
|
||||||
|
Right = 'right',
|
||||||
|
None = 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DataType {
|
||||||
|
Number = 'number',
|
||||||
|
Point = 'point'
|
||||||
|
}
|
||||||
@@ -3,8 +3,9 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ChartInsight, ChartType, customMixin, IChartConfig } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
import { ChartInsight, customMixin, IChartConfig } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
||||||
import { mixin } from 'sql/base/common/objects';
|
import { mixin } from 'sql/base/common/objects';
|
||||||
|
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
|
|
||||||
import { IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import * as colors from 'vs/platform/theme/common/colorRegistry';
|
import * as colors from 'vs/platform/theme/common/colorRegistry';
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
|
||||||
import PieChart from './pieChart.component';
|
import PieChart from './pieChart.component';
|
||||||
|
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
|
|
||||||
export default class DoughnutChart extends PieChart {
|
export default class DoughnutChart extends PieChart {
|
||||||
protected readonly chartType: ChartType = ChartType.Doughnut;
|
protected readonly chartType: ChartType = ChartType.Doughnut;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
|
||||||
import BarChart from './barChart.component';
|
import BarChart from './barChart.component';
|
||||||
|
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
|
|
||||||
export default class HorizontalBarChart extends BarChart {
|
export default class HorizontalBarChart extends BarChart {
|
||||||
protected readonly chartType: ChartType = ChartType.HorizontalBar;
|
protected readonly chartType: ChartType = ChartType.HorizontalBar;
|
||||||
|
|||||||
@@ -3,16 +3,13 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ChartType, customMixin, defaultChartConfig, IDataSet, IPointDataSet } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
import { mixin } from 'vs/base/common/objects';
|
||||||
|
|
||||||
|
import { defaultChartConfig, IDataSet, IPointDataSet } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
||||||
import BarChart, { IBarChartConfig } from './barChart.component';
|
import BarChart, { IBarChartConfig } from './barChart.component';
|
||||||
import { memoize, unmemoize } from 'sql/base/common/decorators';
|
import { memoize, unmemoize } from 'sql/base/common/decorators';
|
||||||
import { mixin } from 'vs/base/common/objects';
|
|
||||||
import { clone } from 'sql/base/common/objects';
|
import { clone } from 'sql/base/common/objects';
|
||||||
|
import { ChartType, DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
export enum DataType {
|
|
||||||
Number = 'number',
|
|
||||||
Point = 'point'
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ILineConfig extends IBarChartConfig {
|
export interface ILineConfig extends IBarChartConfig {
|
||||||
dataType?: DataType;
|
dataType?: DataType;
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ChartInsight, ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
import { ChartInsight } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
||||||
|
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
|
|
||||||
export default class PieChart extends ChartInsight {
|
export default class PieChart extends ChartInsight {
|
||||||
protected readonly chartType: ChartType = ChartType.Pie;
|
protected readonly chartType: ChartType = ChartType.Pie;
|
||||||
|
|||||||
@@ -3,11 +3,12 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ChartType, defaultChartConfig } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
import { defaultChartConfig } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
||||||
import LineChart, { ILineConfig } from './lineChart.component';
|
import LineChart, { ILineConfig } from './lineChart.component';
|
||||||
|
import { clone } from 'sql/base/common/objects';
|
||||||
|
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
|
|
||||||
import { mixin } from 'vs/base/common/objects';
|
import { mixin } from 'vs/base/common/objects';
|
||||||
import { clone } from 'sql/base/common/objects';
|
|
||||||
|
|
||||||
const defaultScatterConfig = mixin(clone(defaultChartConfig), { dataType: 'point', dataDirection: 'horizontal' }) as ILineConfig;
|
const defaultScatterConfig = mixin(clone(defaultChartConfig), { dataType: 'point', dataDirection: 'horizontal' }) as ILineConfig;
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { defaultChartConfig, IPointDataSet, ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
import { defaultChartConfig, IPointDataSet } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
||||||
import LineChart, { ILineConfig } from './lineChart.component';
|
import LineChart, { ILineConfig } from './lineChart.component';
|
||||||
import { clone } from 'sql/base/common/objects';
|
import { clone } from 'sql/base/common/objects';
|
||||||
|
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
|
|
||||||
import { mixin } from 'vs/base/common/objects';
|
import { mixin } from 'vs/base/common/objects';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export class TasksWidget extends DashboardWidget implements IDashboardWidget, On
|
|||||||
}).filter(i => !!i);
|
}).filter(i => !!i);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._tasks = tasks.map(i => TaskRegistry.getCommandActionById(i)).filter(v => !!v);
|
this._tasks = tasks.map(i => MenuRegistry.getCommand(i)).filter(v => !!v);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
<div class="option check" #encryptCheckContainer>
|
<div class="option check" #encryptCheckContainer>
|
||||||
</div>
|
</div>
|
||||||
<div class="option" #encryptWarningContainer>
|
<div class="option" #encryptWarningContainer>
|
||||||
<div class="icon warning">
|
<div class="sql icon warning">
|
||||||
</div>
|
</div>
|
||||||
<div class="warning-message">
|
<div class="warning-message">
|
||||||
{{localizedStrings.NO_ENCRYPTOR_WARNING}}
|
{{localizedStrings.NO_ENCRYPTOR_WARNING}}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ classes should alter those!
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
-o-text-overflow: ellipsis;
|
-o-text-overflow: ellipsis;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
height: 16px;
|
height: 28px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
@@ -35,7 +35,7 @@ classes should alter those!
|
|||||||
border-bottom: 2px solid #bbb;
|
border-bottom: 2px solid #bbb;
|
||||||
float: left;
|
float: left;
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
box-sizing: content-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slick-headerrow-column.ui-state-default, .slick-footerrow-column.ui-state-default {
|
.slick-headerrow-column.ui-state-default, .slick-footerrow-column.ui-state-default {
|
||||||
@@ -104,6 +104,11 @@ classes should alter those!
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.slick-cell .grid-cell-value-container.missing-value {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
.slick-cell, .slick-headerrow-column{
|
.slick-cell, .slick-headerrow-column{
|
||||||
border-bottom-color: silver;
|
border-bottom-color: silver;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
|||||||
|
|
||||||
this.onCellEditEnd = (event: Slick.OnCellChangeEventArgs<any>): void => {
|
this.onCellEditEnd = (event: Slick.OnCellChangeEventArgs<any>): void => {
|
||||||
// Store the value that was set
|
// Store the value that was set
|
||||||
self.currentEditCellValue = event.item[event.cell - 1];
|
self.currentEditCellValue = event.item[event.cell];
|
||||||
};
|
};
|
||||||
|
|
||||||
this.overrideCellFn = (rowNumber, columnId, value?, data?): string => {
|
this.overrideCellFn = (rowNumber, columnId, value?, data?): string => {
|
||||||
@@ -270,18 +270,18 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
|||||||
|
|
||||||
return self.dataService.updateCell(sessionRowId, self.currentCell.column - 1, self.currentEditCellValue)
|
return self.dataService.updateCell(sessionRowId, self.currentCell.column - 1, self.currentEditCellValue)
|
||||||
.then(
|
.then(
|
||||||
result => {
|
result => {
|
||||||
// Cell update was successful, update the flags
|
// Cell update was successful, update the flags
|
||||||
self.currentEditCellValue = null;
|
self.currentEditCellValue = null;
|
||||||
self.setCellDirtyState(row, self.currentCell.column, result.cell.isDirty);
|
self.setCellDirtyState(row, self.currentCell.column, result.cell.isDirty);
|
||||||
self.setRowDirtyState(row, result.isRowDirty);
|
self.setRowDirtyState(row, result.isRowDirty);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
// Cell update failed, jump back to the last cell we were on
|
// Cell update failed, jump back to the last cell we were on
|
||||||
self.focusCell(self.currentCell.row, self.currentCell.column, true);
|
self.focusCell(self.currentCell.row, self.currentCell.column, true);
|
||||||
return Promise.reject(null);
|
return Promise.reject(null);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -377,10 +377,11 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
|||||||
index => { return {}; }
|
index => { return {}; }
|
||||||
),
|
),
|
||||||
columnDefinitions: [rowNumberColumn.getColumnDefinition()].concat(resultSet.columnInfo.map((c, i) => {
|
columnDefinitions: [rowNumberColumn.getColumnDefinition()].concat(resultSet.columnInfo.map((c, i) => {
|
||||||
|
let columnIndex = (i + 1).toString();
|
||||||
return {
|
return {
|
||||||
id: i.toString(),
|
id: columnIndex,
|
||||||
name: escape(c.columnName),
|
name: escape(c.columnName),
|
||||||
field: i.toString(),
|
field: columnIndex,
|
||||||
formatter: Services.textFormatter,
|
formatter: Services.textFormatter,
|
||||||
isEditable: c.isUpdatable
|
isEditable: c.isUpdatable
|
||||||
};
|
};
|
||||||
@@ -464,7 +465,7 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
// Perform a revert row operation
|
// Perform a revert row operation
|
||||||
if (this.currentCell) {
|
if (this.currentCell && this.currentCell.row !== undefined && this.currentCell.row !== null) {
|
||||||
await this.dataService.revertRow(this.currentCell.row);
|
await this.dataService.revertRow(this.currentCell.row);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { IGridDataSet } from 'sql/parts/grid/common/interfaces';
|
|||||||
import { IInsightData, IInsightsView, IInsightsConfig } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
import { IInsightData, IInsightsView, IInsightsConfig } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
||||||
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/common/insightRegistry';
|
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/common/insightRegistry';
|
||||||
import { QueryEditor } from 'sql/parts/query/editor/queryEditor';
|
import { QueryEditor } from 'sql/parts/query/editor/queryEditor';
|
||||||
import { DataType, ILineConfig } from 'sql/parts/dashboard/widgets/insights/views/charts/types/lineChart.component';
|
import { ILineConfig } from 'sql/parts/dashboard/widgets/insights/views/charts/types/lineChart.component';
|
||||||
import * as PathUtilities from 'sql/common/pathUtilities';
|
import * as PathUtilities from 'sql/common/pathUtilities';
|
||||||
import { IChartViewActionContext, CopyAction, CreateInsightAction, SaveImageAction } from 'sql/parts/grid/views/query/chartViewerActions';
|
import { IChartViewActionContext, CopyAction, CreateInsightAction, SaveImageAction } from 'sql/parts/grid/views/query/chartViewerActions';
|
||||||
import * as WorkbenchUtils from 'sql/workbench/common/sqlWorkbenchUtils';
|
import * as WorkbenchUtils from 'sql/workbench/common/sqlWorkbenchUtils';
|
||||||
@@ -24,10 +24,11 @@ import * as Constants from 'sql/parts/query/common/constants';
|
|||||||
import { SelectBox as AngularSelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component';
|
import { SelectBox as AngularSelectBox } from 'sql/base/browser/ui/selectBox/selectBox.component';
|
||||||
import { IQueryModelService } from 'sql/parts/query/execution/queryModel';
|
import { IQueryModelService } from 'sql/parts/query/execution/queryModel';
|
||||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||||
|
import { LegendPosition, DataDirection, DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
|
|
||||||
/* Insights */
|
/* Insights */
|
||||||
import {
|
import {
|
||||||
ChartInsight, DataDirection, LegendPosition
|
ChartInsight
|
||||||
} from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
} from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
||||||
|
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
|||||||
@@ -188,8 +188,16 @@ export class InsightsDialogView extends Modal {
|
|||||||
for (let i = 0; i < this._model.columns.length; i++) {
|
for (let i = 0; i < this._model.columns.length; i++) {
|
||||||
resourceArray.push({ label: this._model.columns[i], value: element.data[i], data: element.data });
|
resourceArray.push({ label: this._model.columns[i], value: element.data[i], data: element.data });
|
||||||
}
|
}
|
||||||
|
|
||||||
this._bottomTableData.clear();
|
this._bottomTableData.clear();
|
||||||
this._bottomTableData.push(resourceArray);
|
this._bottomTableData.push(resourceArray);
|
||||||
|
// this table view has to be collapsed and expanded
|
||||||
|
// because the initial expand doesn't have the
|
||||||
|
// loaded data
|
||||||
|
if (bottomTableView.isExpanded()) {
|
||||||
|
bottomTableView.collapse();
|
||||||
|
bottomTableView.expand();
|
||||||
|
}
|
||||||
this._enableTaskButtons(true);
|
this._enableTaskButtons(true);
|
||||||
} else {
|
} else {
|
||||||
this._enableTaskButtons(false);
|
this._enableTaskButtons(false);
|
||||||
@@ -334,6 +342,7 @@ export class InsightsDialogView extends Modal {
|
|||||||
this.hide();
|
this.hide();
|
||||||
dispose(this._taskButtonDisposables);
|
dispose(this._taskButtonDisposables);
|
||||||
this._taskButtonDisposables = [];
|
this._taskButtonDisposables = [];
|
||||||
|
this.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onClose(e: StandardKeyboardEvent) {
|
protected onClose(e: StandardKeyboardEvent) {
|
||||||
|
|||||||
@@ -70,8 +70,7 @@ export abstract class JobManagementView extends TabChild implements AfterContent
|
|||||||
abstract onFirstVisible();
|
abstract onFirstVisible();
|
||||||
|
|
||||||
protected openContextMenu(event): void {
|
protected openContextMenu(event): void {
|
||||||
let grid = this._table.grid;
|
let rowIndex = event.cell.row;
|
||||||
let rowIndex = grid.getCellFromEvent(event).row;
|
|
||||||
|
|
||||||
let targetObject = this.getCurrentTableObject(rowIndex);
|
let targetObject = this.getCurrentTableObject(rowIndex);
|
||||||
let actions = this.getTableActions();
|
let actions = this.getTableActions();
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ import * as sqlops from 'sqlops';
|
|||||||
import { ComponentWithIconBase } from 'sql/parts/modelComponents/componentWithIconBase';
|
import { ComponentWithIconBase } from 'sql/parts/modelComponents/componentWithIconBase';
|
||||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||||
import { attachButtonStyler } from 'sql/common/theme/styler';
|
import { attachButtonStyler } from 'sql/common/theme/styler';
|
||||||
import { Button } from 'sql/base/browser/ui/button/button';
|
|
||||||
|
|
||||||
import { SIDE_BAR_BACKGROUND, SIDE_BAR_TITLE_FOREGROUND } from 'vs/workbench/common/theme';
|
import { SIDE_BAR_BACKGROUND, SIDE_BAR_TITLE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import { focusBorder, foreground } from 'vs/platform/theme/common/colorRegistry';
|
import { focusBorder, foreground } from 'vs/platform/theme/common/colorRegistry';
|
||||||
|
import { Button } from 'sql/base/browser/ui/button/button';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
|
|
||||||
|
|
||||||
@@ -101,6 +101,7 @@ export default class ButtonComponent extends ComponentWithIconBase implements IC
|
|||||||
super.setProperties(properties);
|
super.setProperties(properties);
|
||||||
this._button.enabled = this.enabled;
|
this._button.enabled = this.enabled;
|
||||||
this._button.label = this.label;
|
this._button.label = this.label;
|
||||||
|
this._button.title = this.title;
|
||||||
if (this.width) {
|
if (this.width) {
|
||||||
this._button.setWidth(this.convertSize(this.width.toString()));
|
this._button.setWidth(this.convertSize(this.width.toString()));
|
||||||
}
|
}
|
||||||
@@ -165,4 +166,13 @@ export default class ButtonComponent extends ComponentWithIconBase implements IC
|
|||||||
private setFileProperties(properties: sqlops.ButtonProperties, isFile: boolean): void {
|
private setFileProperties(properties: sqlops.ButtonProperties, isFile: boolean): void {
|
||||||
properties.isFile = isFile;
|
properties.isFile = isFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get title(): string {
|
||||||
|
return this.getPropertyOrDefault<sqlops.ButtonProperties, string>((props) => props.title, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
private set title(newValue: string) {
|
||||||
|
this.setPropertyFromUI<sqlops.ButtonProperties, string>((properties, title) => { properties.title = title; }, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ export class ItemDescriptor<T> {
|
|||||||
constructor(public descriptor: IComponentDescriptor, public config: T) { }
|
constructor(public descriptor: IComponentDescriptor, public config: T) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ids = new IdGenerator('model-view-component-icon-');
|
||||||
|
|
||||||
export abstract class ComponentWithIconBase extends ComponentBase {
|
export abstract class ComponentWithIconBase extends ComponentBase {
|
||||||
|
|
||||||
protected _iconClass: string;
|
protected _iconClass: string;
|
||||||
@@ -42,7 +44,6 @@ export abstract class ComponentWithIconBase extends ComponentBase {
|
|||||||
if (this.iconPath && this.iconPath !== this._iconPath) {
|
if (this.iconPath && this.iconPath !== this._iconPath) {
|
||||||
this._iconPath = this.iconPath;
|
this._iconPath = this.iconPath;
|
||||||
if (!this._iconClass) {
|
if (!this._iconClass) {
|
||||||
const ids = new IdGenerator('model-view-component-icon-' + Math.round(Math.random() * 1000));
|
|
||||||
this._iconClass = ids.nextId();
|
this._iconClass = ids.nextId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
import DivContainer from './divContainer.component';
|
||||||
import FlexContainer from './flexContainer.component';
|
import FlexContainer from './flexContainer.component';
|
||||||
import FormContainer from './formContainer.component';
|
import FormContainer from './formContainer.component';
|
||||||
import ToolbarContainer from './toolbarContainer.component';
|
import ToolbarContainer from './toolbarContainer.component';
|
||||||
@@ -22,9 +22,13 @@ import TextComponent from './text.component';
|
|||||||
import LoadingComponent from './loadingComponent.component';
|
import LoadingComponent from './loadingComponent.component';
|
||||||
import FileBrowserTreeComponent from './fileBrowserTree.component';
|
import FileBrowserTreeComponent from './fileBrowserTree.component';
|
||||||
import EditorComponent from './editor.component';
|
import EditorComponent from './editor.component';
|
||||||
|
import DomComponent from './dom.component';
|
||||||
import { registerComponentType } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
import { registerComponentType } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
||||||
import { ModelComponentTypes } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { ModelComponentTypes } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
|
export const DIV_CONTAINER = 'div-container';
|
||||||
|
registerComponentType(DIV_CONTAINER, ModelComponentTypes.DivContainer, DivContainer);
|
||||||
|
|
||||||
export const FLEX_CONTAINER = 'flex-container';
|
export const FLEX_CONTAINER = 'flex-container';
|
||||||
registerComponentType(FLEX_CONTAINER, ModelComponentTypes.FlexContainer, FlexContainer);
|
registerComponentType(FLEX_CONTAINER, ModelComponentTypes.FlexContainer, FlexContainer);
|
||||||
|
|
||||||
@@ -82,3 +86,6 @@ registerComponentType(FILEBROWSERTREE_COMPONENT, ModelComponentTypes.FileBrowser
|
|||||||
|
|
||||||
export const EDITOR_COMPONENT = 'editor-component';
|
export const EDITOR_COMPONENT = 'editor-component';
|
||||||
registerComponentType(EDITOR_COMPONENT, ModelComponentTypes.Editor, EditorComponent);
|
registerComponentType(EDITOR_COMPONENT, ModelComponentTypes.Editor, EditorComponent);
|
||||||
|
|
||||||
|
export const DOM_COMPONENT = 'dom-component';
|
||||||
|
registerComponentType(DOM_COMPONENT, ModelComponentTypes.Dom, DomComponent);
|
||||||
|
|||||||
120
src/sql/parts/modelComponents/divContainer.component.ts
Normal file
120
src/sql/parts/modelComponents/divContainer.component.ts
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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!./divContainer';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
||||||
|
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList,
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import { IComponent, IComponentDescriptor, IModelStore } from 'sql/parts/modelComponents/interfaces';
|
||||||
|
import * as sqlops from 'sqlops';
|
||||||
|
|
||||||
|
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||||
|
import { ContainerBase } from 'sql/parts/modelComponents/componentBase';
|
||||||
|
import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component';
|
||||||
|
|
||||||
|
import types = require('vs/base/common/types');
|
||||||
|
|
||||||
|
class DivItem {
|
||||||
|
constructor(public descriptor: IComponentDescriptor, public config: sqlops.DivItemLayout) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
template: `
|
||||||
|
<div #divContainer *ngIf="items" class="divContainer" [style.height]="height" [style.width]="width">
|
||||||
|
<div *ngFor="let item of items" [style.order]="getItemOrder(item)" [ngStyle]="getItemStyles(item)">
|
||||||
|
<model-component-wrapper [descriptor]="item.descriptor" [modelStore]="modelStore">
|
||||||
|
</model-component-wrapper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export default class DivContainer extends ContainerBase<sqlops.DivItemLayout> implements IComponent, OnDestroy {
|
||||||
|
@Input() descriptor: IComponentDescriptor;
|
||||||
|
@Input() modelStore: IModelStore;
|
||||||
|
@ViewChild('divContainer', { read: ElementRef }) divContainer;
|
||||||
|
private _height: string;
|
||||||
|
private _width: string;
|
||||||
|
private _overflowY: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
|
||||||
|
@Inject(forwardRef(() => ElementRef)) el: ElementRef
|
||||||
|
) {
|
||||||
|
super(changeRef, el);
|
||||||
|
this._overflowY = ''; // default
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.baseInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.baseDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// IComponent implementation
|
||||||
|
|
||||||
|
public setLayout(layout: sqlops.DivLayout): void {
|
||||||
|
this._height = this.convertSize(layout.height);
|
||||||
|
this._width = this.convertSize(layout.width);
|
||||||
|
this.layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public setProperties(properties: { [key: string]: any; }): void {
|
||||||
|
super.setProperties(properties);
|
||||||
|
if (this.overflowY !== this._overflowY) {
|
||||||
|
this.updateOverflowY();
|
||||||
|
}
|
||||||
|
this.updateScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateOverflowY() {
|
||||||
|
this._overflowY = this.overflowY;
|
||||||
|
if (this._overflowY) {
|
||||||
|
let element = <HTMLElement> this.divContainer.nativeElement;
|
||||||
|
element.style.overflowY = this._overflowY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateScroll() {
|
||||||
|
let element = <HTMLElement> this.divContainer.nativeElement;
|
||||||
|
element.scrollTop = element.scrollTop - this.yOffsetChange;
|
||||||
|
element.dispatchEvent(new Event('scroll'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSS-bound properties
|
||||||
|
public get height(): string {
|
||||||
|
return this._height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get width(): string {
|
||||||
|
return this._width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSS-bound properties
|
||||||
|
public get overflowY(): string {
|
||||||
|
return this.getPropertyOrDefault<sqlops.DivContainerProperties, any>((props) => props.overflowY, '');
|
||||||
|
}
|
||||||
|
public set overflowY(newValue: string) {
|
||||||
|
this.setPropertyFromUI<sqlops.DivContainerProperties, any>((properties, newValue) => { properties.overflowY = newValue; }, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get yOffsetChange(): number {
|
||||||
|
return this.getPropertyOrDefault<sqlops.DivContainerProperties, any>((props) => props.yOffsetChange, 0);
|
||||||
|
}
|
||||||
|
public set yOffsetChange(newValue: number) {
|
||||||
|
this.setPropertyFromUI<sqlops.DivContainerProperties, any>((properties, newValue) => { properties.yOffsetChange = newValue; }, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getItemOrder(item: DivItem): number {
|
||||||
|
return item.config ? item.config.order : 0;
|
||||||
|
}
|
||||||
|
private getItemStyles(item: DivItem): { [key: string]: string } {
|
||||||
|
return item.config && item.config.CSSStyles ? item.config.CSSStyles : {};
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/sql/parts/modelComponents/divContainer.css
Normal file
5
src/sql/parts/modelComponents/divContainer.css
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
.divContainer {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
92
src/sql/parts/modelComponents/dom.component.ts
Normal file
92
src/sql/parts/modelComponents/dom.component.ts
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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!./dom';
|
||||||
|
import 'vs/css!./highlight';
|
||||||
|
import 'vs/css!./markdown';
|
||||||
|
import {
|
||||||
|
Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
||||||
|
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import * as sqlops from 'sqlops';
|
||||||
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
|
import { $, Builder } from 'vs/base/browser/builder';
|
||||||
|
|
||||||
|
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
||||||
|
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
template: '',
|
||||||
|
selector: 'modelview-dom-component'
|
||||||
|
})
|
||||||
|
export default class DomComponent extends ComponentBase implements IComponent, OnDestroy {
|
||||||
|
@Input() descriptor: IComponentDescriptor;
|
||||||
|
@Input() modelStore: IModelStore;
|
||||||
|
private _renderedHtml: string;
|
||||||
|
private _rootElement: Builder;
|
||||||
|
private _bodyElement: Builder;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
|
||||||
|
@Inject(forwardRef(() => ElementRef)) el: ElementRef
|
||||||
|
) {
|
||||||
|
super(changeRef, el);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.baseInit();
|
||||||
|
this.createDomElement();
|
||||||
|
this._register(DOM.addDisposableListener(window, DOM.EventType.RESIZE, e => {
|
||||||
|
this.layout();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.baseDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private createDomElement() {
|
||||||
|
this._rootElement = new Builder(this._el.nativeElement);
|
||||||
|
this._bodyElement = $('.dom-body');
|
||||||
|
this._rootElement.append(this._bodyElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dom Functions
|
||||||
|
private setHtml(): void {
|
||||||
|
if (this.html) {
|
||||||
|
this._renderedHtml = this.html;
|
||||||
|
this._bodyElement.innerHtml(this._renderedHtml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IComponent implementation
|
||||||
|
public layout(): void {
|
||||||
|
super.layout();
|
||||||
|
let element = <HTMLElement>this._el.nativeElement;
|
||||||
|
element.style.width = this.getWidth();
|
||||||
|
element.style.height = this.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
public setLayout(layout: any): void {
|
||||||
|
// TODO allow configuring the look and feel
|
||||||
|
this.layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public setProperties(properties: { [key: string]: any; }): void {
|
||||||
|
super.setProperties(properties);
|
||||||
|
if (this.html !== this._renderedHtml) {
|
||||||
|
this.setHtml();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSS-bound properties
|
||||||
|
public get html(): string {
|
||||||
|
return this.getPropertyOrDefault<sqlops.DomProperties, string>((props) => props.html, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
public set html(newValue: string) {
|
||||||
|
this.setPropertyFromUI<sqlops.DomProperties, string>((properties, html) => { properties.html = html; }, newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/sql/parts/modelComponents/dom.css
Normal file
9
src/sql/parts/modelComponents/dom.css
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
modelview-dom-component {
|
||||||
|
display: block;
|
||||||
|
-webkit-user-select: text;
|
||||||
|
}
|
||||||
183
src/sql/parts/modelComponents/highlight.css
Normal file
183
src/sql/parts/modelComponents/highlight.css
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
https://raw.githubusercontent.com/isagalaev/highlight.js/master/src/styles/vs2015.css
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Visual Studio 2015 dark style
|
||||||
|
* Author: Nicolas LLOBERA <nllobera@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-keyword,
|
||||||
|
modelview-dom-component .hljs-literal,
|
||||||
|
modelview-dom-component .hljs-symbol,
|
||||||
|
modelview-dom-component .hljs-name {
|
||||||
|
color: #569CD6;
|
||||||
|
}
|
||||||
|
modelview-dom-component .hljs-link {
|
||||||
|
color: #569CD6;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-built_in,
|
||||||
|
modelview-dom-component .hljs-type {
|
||||||
|
color: #4EC9B0;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-number,
|
||||||
|
modelview-dom-component .hljs-class {
|
||||||
|
color: #B8D7A3;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-string,
|
||||||
|
modelview-dom-component .hljs-meta-string {
|
||||||
|
color: #D69D85;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-regexp,
|
||||||
|
modelview-dom-component .hljs-template-tag {
|
||||||
|
color: #9A5334;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-subst,
|
||||||
|
modelview-dom-component .hljs-function,
|
||||||
|
modelview-dom-component .hljs-title,
|
||||||
|
modelview-dom-component .hljs-params,
|
||||||
|
modelview-dom-component .hljs-formula {
|
||||||
|
color: #DCDCDC;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-comment,
|
||||||
|
modelview-dom-component .hljs-quote {
|
||||||
|
color: #57A64A;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-doctag {
|
||||||
|
color: #608B4E;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-meta,
|
||||||
|
modelview-dom-component .hljs-meta-keyword,
|
||||||
|
modelview-dom-component .hljs-tag {
|
||||||
|
color: #9B9B9B;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-variable,
|
||||||
|
modelview-dom-component .hljs-template-variable {
|
||||||
|
color: #BD63C5;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-attr,
|
||||||
|
modelview-dom-component .hljs-attribute,
|
||||||
|
modelview-dom-component .hljs-builtin-name {
|
||||||
|
color: #9CDCFE;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-section {
|
||||||
|
color: gold;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-emphasis {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*.hljs-code {
|
||||||
|
font-family:'Monospace';
|
||||||
|
}*/
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-bullet,
|
||||||
|
modelview-dom-component .hljs-selector-tag,
|
||||||
|
modelview-dom-component .hljs-selector-id,
|
||||||
|
modelview-dom-component .hljs-selector-class,
|
||||||
|
modelview-dom-component .hljs-selector-attr,
|
||||||
|
modelview-dom-component .hljs-selector-pseudo {
|
||||||
|
color: #D7BA7D;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-addition {
|
||||||
|
background-color: #144212;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .hljs-deletion {
|
||||||
|
background-color: #600;
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
From https://raw.githubusercontent.com/isagalaev/highlight.js/master/src/styles/vs.css
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
|
||||||
|
Visual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name>
|
||||||
|
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
.vscode-light .hljs-function,
|
||||||
|
.vscode-light .hljs-params {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vscode-light .hljs-comment,
|
||||||
|
.vscode-light .hljs-quote,
|
||||||
|
.vscode-light .hljs-variable {
|
||||||
|
color: #008000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vscode-light .hljs-keyword,
|
||||||
|
.vscode-light .hljs-selector-tag,
|
||||||
|
.vscode-light .hljs-built_in,
|
||||||
|
.vscode-light .hljs-name,
|
||||||
|
.vscode-light .hljs-tag {
|
||||||
|
color: #00f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vscode-light .hljs-string,
|
||||||
|
.vscode-light .hljs-title,
|
||||||
|
.vscode-light .hljs-section,
|
||||||
|
.vscode-light .hljs-attribute,
|
||||||
|
.vscode-light .hljs-literal,
|
||||||
|
.vscode-light .hljs-template-tag,
|
||||||
|
.vscode-light .hljs-template-variable,
|
||||||
|
.vscode-light .hljs-type,
|
||||||
|
.vscode-light .hljs-addition {
|
||||||
|
color: #a31515;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vscode-light .hljs-deletion,
|
||||||
|
.vscode-light .hljs-selector-attr,
|
||||||
|
.vscode-light .hljs-selector-pseudo,
|
||||||
|
.vscode-light .hljs-meta {
|
||||||
|
color: #2b91af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vscode-light .hljs-doctag {
|
||||||
|
color: #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vscode-light .hljs-attr {
|
||||||
|
color: #f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vscode-light .hljs-symbol,
|
||||||
|
.vscode-light .hljs-bullet,
|
||||||
|
.vscode-light .hljs-link {
|
||||||
|
color: #00b0e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.vscode-light .hljs-emphasis {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vscode-light .hljs-strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
*/
|
||||||
238
src/sql/parts/modelComponents/markdown.css
Normal file
238
src/sql/parts/modelComponents/markdown.css
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
modelview-dom-component {
|
||||||
|
font-family: "Segoe WPC", "Segoe UI", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback";
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 0 26px;
|
||||||
|
line-height: 22px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component #code-csp-warning {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
color: white;
|
||||||
|
margin: 16px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
background-color:#444444;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 6px;
|
||||||
|
box-shadow: 1px 1px 1px rgba(0,0,0,.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component #code-csp-warning:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
background-color:#007acc;
|
||||||
|
box-shadow: 2px 2px 2px rgba(0,0,0,.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
modelview-dom-component .scrollBeyondLastLine {
|
||||||
|
margin-bottom: calc(100vh - 22px);
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .showEditorSelection .code-line {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .showEditorSelection .code-active-line:before,
|
||||||
|
modelview-dom-component .showEditorSelection .code-line:hover:before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -12px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .showEditorSelection li.code-active-line:before,
|
||||||
|
modelview-dom-component .showEditorSelection li.code-line:hover:before {
|
||||||
|
left: -30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .showEditorSelection .code-active-line:before {
|
||||||
|
border-left: 3px solid rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .showEditorSelection .code-line:hover:before {
|
||||||
|
border-left: 3px solid rgba(0, 0, 0, 0.40);
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .showEditorSelection .code-line .code-line:hover:before {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-dark .monaco-workbench modelview-dom-component .showEditorSelection .code-active-line:before
|
||||||
|
.hc-black .monaco-workbench modelview-dom-component .showEditorSelection .code-active-line:before {
|
||||||
|
border-left: 3px solid rgba(255, 255, 255, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-dark .monaco-workbench modelview-dom-component .showEditorSelection .code-line:hover:before
|
||||||
|
.hc-black .monaco-workbench modelview-dom-component .showEditorSelection .code-line:hover:before {
|
||||||
|
border-left: 3px solid rgba(255, 255, 255, 0.60);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-dark .monaco-workbench modelview-dom-component .showEditorSelection .code-line .code-line:hover:before
|
||||||
|
.hc-black .monaco-workbench modelview-dom-component .showEditorSelection .code-line .code-line:hover:before {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hc-black modelview-dom-component .showEditorSelection .code-active-line:before {
|
||||||
|
border-left: 3px solid rgba(255, 160, 0, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hc-black modelview-dom-component .showEditorSelection .code-line:hover:before {
|
||||||
|
border-left: 3px solid rgba(255, 160, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .showEditorSelection .code-line .code-line:hover:before {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component a, modelview-dom-component a:link{
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component a:hover, modelview-dom-component a:link {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component a:focus,
|
||||||
|
modelview-dom-component input:focus,
|
||||||
|
modelview-dom-component select:focus,
|
||||||
|
modelview-dom-component textarea:focus {
|
||||||
|
outline: 1px solid -webkit-focus-ring-color;
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component hr {
|
||||||
|
border: 0;
|
||||||
|
height: 2px;
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component h1 {
|
||||||
|
padding-bottom: 0.3em;
|
||||||
|
line-height: 1.2;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component h1,
|
||||||
|
modelview-dom-component h2,
|
||||||
|
modelview-dom-component h3 {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component h1 code,
|
||||||
|
modelview-dom-component h2 code,
|
||||||
|
modelview-dom-component h3 code,
|
||||||
|
modelview-dom-component h4 code,
|
||||||
|
modelview-dom-component h5 code,
|
||||||
|
modelview-dom-component h6 code {
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component table > thead > tr > th {
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component table > thead > tr > th,
|
||||||
|
modelview-dom-component table > thead > tr > td,
|
||||||
|
modelview-dom-component table > tbody > tr > th,
|
||||||
|
modelview-dom-component table > tbody > tr > td {
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component table > tbody > tr + tr > td {
|
||||||
|
border-top: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component blockquote {
|
||||||
|
margin: 0 7px 0 5px;
|
||||||
|
padding: 0 16px 0 10px;
|
||||||
|
border-left-width: 5px;
|
||||||
|
border-left-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component code {
|
||||||
|
font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback";
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 19px;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .wordWrap pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component .mac code {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component pre:not(.hljs),
|
||||||
|
modelview-dom-component pre.hljs code > div {
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 3px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Theming */
|
||||||
|
|
||||||
|
modelview-dom-component pre code {
|
||||||
|
color: var(--vscode-editor-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
modelview-dom-component pre {
|
||||||
|
background-color: rgba(220, 220, 220, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-dark .monaco-workbench modelview-dom-component pre {
|
||||||
|
background-color: rgba(10, 10, 10, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hc-black .monaco-workbench modelview-dom-component pre {
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hc-black .monaco-workbench modelview-dom-component h1 {
|
||||||
|
border-color: rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component table > thead > tr > th {
|
||||||
|
border-color: rgba(0, 0, 0, 0.69);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-dark .monaco-workbench modelview-dom-component table > thead > tr > th {
|
||||||
|
border-color: rgba(255, 255, 255, 0.69);
|
||||||
|
}
|
||||||
|
|
||||||
|
modelview-dom-component h1,
|
||||||
|
modelview-dom-component hr,
|
||||||
|
modelview-dom-component table > tbody > tr + tr > td {
|
||||||
|
border-color: rgba(0, 0, 0, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-dark .monaco-workbench modelview-dom-component h1,
|
||||||
|
.vs-dark .monaco-workbench modelview-dom-component hr,
|
||||||
|
.vs-dark .monaco-workbench modelview-dom-component table > tbody > tr + tr > td {
|
||||||
|
border-color: rgba(255, 255, 255, 0.18);
|
||||||
|
}
|
||||||
@@ -3,16 +3,50 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as sqlops from 'sqlops';
|
||||||
|
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { IEditorModel } from 'vs/platform/editor/common/editor';
|
import { IEditorModel } from 'vs/platform/editor/common/editor';
|
||||||
import { EditorInput } from 'vs/workbench/common/editor';
|
import { EditorInput, EditorModel, ConfirmResult } from 'vs/workbench/common/editor';
|
||||||
import * as DOM from 'vs/base/browser/dom';
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
|
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
|
||||||
|
|
||||||
import { DialogPane } from 'sql/platform/dialog/dialogPane';
|
import { DialogPane } from 'sql/platform/dialog/dialogPane';
|
||||||
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
|
|
||||||
import * as sqlops from 'sqlops';
|
export type ModeViewSaveHandler = (handle: number) => Thenable<boolean>;
|
||||||
|
|
||||||
|
export class ModelViewInputModel extends EditorModel {
|
||||||
|
private dirty: boolean;
|
||||||
|
private readonly _onDidChangeDirty: Emitter<void> = this._register(new Emitter<void>());
|
||||||
|
get onDidChangeDirty(): Event<void> { return this._onDidChangeDirty.event; }
|
||||||
|
|
||||||
|
constructor(public readonly modelViewId, private readonly handle: number, private saveHandler?: ModeViewSaveHandler) {
|
||||||
|
super();
|
||||||
|
this.dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isDirty(): boolean {
|
||||||
|
return this.dirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setDirty(dirty: boolean): void {
|
||||||
|
if (this.dirty === dirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dirty = dirty;
|
||||||
|
this._onDidChangeDirty.fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
save(): TPromise<boolean> {
|
||||||
|
if (this.saveHandler) {
|
||||||
|
return TPromise.wrap(this.saveHandler(this.handle));
|
||||||
|
}
|
||||||
|
return TPromise.wrap(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
export class ModelViewInput extends EditorInput {
|
export class ModelViewInput extends EditorInput {
|
||||||
|
|
||||||
public static ID: string = 'workbench.editorinputs.ModelViewEditorInput';
|
public static ID: string = 'workbench.editorinputs.ModelViewEditorInput';
|
||||||
@@ -20,14 +54,15 @@ export class ModelViewInput extends EditorInput {
|
|||||||
private _dialogPaneContainer: HTMLElement;
|
private _dialogPaneContainer: HTMLElement;
|
||||||
private _dialogPane: DialogPane;
|
private _dialogPane: DialogPane;
|
||||||
|
|
||||||
constructor(private _title: string, private _modelViewId: string,
|
constructor(private _title: string, private _model: ModelViewInputModel,
|
||||||
private _options: sqlops.ModelViewEditorOptions,
|
private _options: sqlops.ModelViewEditorOptions,
|
||||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||||
@IPartService private readonly _partService: IPartService
|
@IPartService private readonly _partService: IPartService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
this._model.onDidChangeDirty(() => this._onDidChangeDirty.fire());
|
||||||
this._container = document.createElement('div');
|
this._container = document.createElement('div');
|
||||||
this._container.id = `modelView-${_modelViewId}`;
|
this._container.id = `modelView-${_model.modelViewId}`;
|
||||||
this._partService.getContainer(Parts.EDITOR_PART).appendChild(this._container);
|
this._partService.getContainer(Parts.EDITOR_PART).appendChild(this._container);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -37,7 +72,7 @@ export class ModelViewInput extends EditorInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get modelViewId(): string {
|
public get modelViewId(): string {
|
||||||
return this._modelViewId;
|
return this._model.modelViewId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTypeId(): string {
|
public getTypeId(): string {
|
||||||
@@ -85,6 +120,31 @@ export class ModelViewInput extends EditorInput {
|
|||||||
return this._options;
|
return this._options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An editor that is dirty will be asked to be saved once it closes.
|
||||||
|
*/
|
||||||
|
isDirty(): boolean {
|
||||||
|
return this._model.isDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses should bring up a proper dialog for the user if the editor is dirty and return the result.
|
||||||
|
*/
|
||||||
|
confirmSave(): TPromise<ConfirmResult> {
|
||||||
|
// TODO #2530 support save on close / confirm save. This is significantly more work
|
||||||
|
// as we need to either integrate with textFileService (seems like this isn't viable)
|
||||||
|
// or register our own complimentary service that handles the lifecycle operations such
|
||||||
|
// as close all, auto save etc.
|
||||||
|
return TPromise.wrap(ConfirmResult.DONT_SAVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the editor if it is dirty. Subclasses return a promise with a boolean indicating the success of the operation.
|
||||||
|
*/
|
||||||
|
save(): TPromise<boolean> {
|
||||||
|
return this._model.save();
|
||||||
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
if (this._dialogPane) {
|
if (this._dialogPane) {
|
||||||
this._dialogPane.dispose();
|
this._dialogPane.dispose();
|
||||||
@@ -93,6 +153,9 @@ export class ModelViewInput extends EditorInput {
|
|||||||
this._container.remove();
|
this._container.remove();
|
||||||
this._container = undefined;
|
this._container = undefined;
|
||||||
}
|
}
|
||||||
|
if (this._model) {
|
||||||
|
this._model.dispose();
|
||||||
|
}
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export class ToolbarItem {
|
|||||||
template: `
|
template: `
|
||||||
<div #container *ngIf="items" [class]="toolbarClass" >
|
<div #container *ngIf="items" [class]="toolbarClass" >
|
||||||
<ng-container *ngFor="let item of items">
|
<ng-container *ngFor="let item of items">
|
||||||
<div class="modelview-toolbar-item" [title]="getItemTitle(item)" [style.paddingTop]="paddingTop" tabindex="0">
|
<div class="modelview-toolbar-item" [style.paddingTop]="paddingTop">
|
||||||
<div *ngIf="shouldShowTitle(item)" class="modelview-toolbar-title" >
|
<div *ngIf="shouldShowTitle(item)" class="modelview-toolbar-title" >
|
||||||
{{getItemTitle(item)}}
|
{{getItemTitle(item)}}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -62,4 +62,12 @@
|
|||||||
margin-right: 0.3em;
|
margin-right: 0.3em;
|
||||||
background-position: 50% 50%;
|
background-position: 50% 50%;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modelview-toolbar-container .modelview-toolbar-component modelview-button .monaco-text-button.active {
|
||||||
|
-ms-transform: scale(1.272019649, 1.272019649); /* 1.272019649 = √φ */
|
||||||
|
-webkit-transform: scale(1.272019649, 1.272019649);
|
||||||
|
-moz-transform: scale(1.272019649, 1.272019649);
|
||||||
|
-o-transform: scale(1.272019649, 1.272019649);
|
||||||
|
transform: scale(1.272019649, 1.272019649);
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ export interface IObjectExplorerService {
|
|||||||
getActiveConnectionNodes(): TreeNode[];
|
getActiveConnectionNodes(): TreeNode[];
|
||||||
|
|
||||||
getTreeNode(connectionId: string, nodePath: string): Thenable<TreeNode>;
|
getTreeNode(connectionId: string, nodePath: string): Thenable<TreeNode>;
|
||||||
|
|
||||||
|
refreshNodeInView(connectionId: string, nodePath: string): Thenable<TreeNode>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SessionStatus {
|
interface SessionStatus {
|
||||||
@@ -476,6 +478,20 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
|||||||
return Object.values(this._activeObjectExplorerNodes);
|
return Object.values(this._activeObjectExplorerNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async refreshNodeInView(connectionId: string, nodePath: string): Promise<TreeNode> {
|
||||||
|
// Get the tree node and call refresh from the provider
|
||||||
|
let treeNode = await this.getTreeNode(connectionId, nodePath);
|
||||||
|
await this.refreshTreeNode(treeNode.getSession(), treeNode);
|
||||||
|
|
||||||
|
// Get the new tree node, refresh it in the view, and expand it if needed
|
||||||
|
treeNode = await this.getTreeNode(connectionId, nodePath);
|
||||||
|
await this._serverTreeView.refreshElement(treeNode);
|
||||||
|
if (treeNode.children.length > 0) {
|
||||||
|
await treeNode.setExpandedState(TreeItemCollapsibleState.Expanded);
|
||||||
|
}
|
||||||
|
return treeNode;
|
||||||
|
}
|
||||||
|
|
||||||
private async setNodeExpandedState(treeNode: TreeNode, expandedState: TreeItemCollapsibleState): Promise<void> {
|
private async setNodeExpandedState(treeNode: TreeNode, expandedState: TreeItemCollapsibleState): Promise<void> {
|
||||||
treeNode = await this.getUpdatedTreeNode(treeNode);
|
treeNode = await this.getUpdatedTreeNode(treeNode);
|
||||||
let expandNode = this.getTreeItem(treeNode);
|
let expandNode = this.getTreeItem(treeNode);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ const viewletDescriptor = new ViewletDescriptor(
|
|||||||
VIEWLET_ID,
|
VIEWLET_ID,
|
||||||
'Servers',
|
'Servers',
|
||||||
'connectionViewlet',
|
'connectionViewlet',
|
||||||
-100
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);
|
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);
|
||||||
|
|||||||
@@ -167,12 +167,12 @@ export class ServerTreeActionProvider extends ContributableActionProvider {
|
|||||||
if (TreeUpdateUtils.isDatabaseNode(treeNode)) {
|
if (TreeUpdateUtils.isDatabaseNode(treeNode)) {
|
||||||
if (TreeUpdateUtils.isAvailableDatabaseNode(treeNode)) {
|
if (TreeUpdateUtils.isAvailableDatabaseNode(treeNode)) {
|
||||||
actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL, context.tree));
|
actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL, context.tree));
|
||||||
|
this.addNewQueryAction(context, actions);
|
||||||
} else {
|
} else {
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addNewQueryAction(context, actions);
|
|
||||||
this.addScriptingActions(context, actions);
|
this.addScriptingActions(context, actions);
|
||||||
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, context.tree, treeNode));
|
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, context.tree, treeNode));
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
import { ConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
|
import { ConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
|
||||||
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
||||||
import { ITree, IDataSource } from 'vs/base/parts/tree/browser/tree';
|
import { ITree, IDataSource } from 'vs/base/parts/tree/browser/tree';
|
||||||
import { TreeNode } from 'sql/parts/objectExplorer/common/treeNode';
|
import { TreeNode, TreeItemCollapsibleState } from 'sql/parts/objectExplorer/common/treeNode';
|
||||||
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { TreeUpdateUtils } from 'sql/parts/objectExplorer/viewlet/treeUpdateUtils';
|
import { TreeUpdateUtils } from 'sql/parts/objectExplorer/viewlet/treeUpdateUtils';
|
||||||
@@ -72,9 +72,13 @@ export class ServerTreeDataSource implements IDataSource {
|
|||||||
if (node.children) {
|
if (node.children) {
|
||||||
resolve(node.children);
|
resolve(node.children);
|
||||||
} else {
|
} else {
|
||||||
|
// These similar changes are probably needed for a ConnectionProfile group element as well. However, we do not have a repro of a failiure in that scenario so they will be tackled in a future checkin.
|
||||||
|
// It has been tested for connecting to the server in profile itself and things work fine there.
|
||||||
this._objectExplorerService.resolveTreeNodeChildren(node.getSession(), node).then(() => {
|
this._objectExplorerService.resolveTreeNodeChildren(node.getSession(), node).then(() => {
|
||||||
resolve(node.children);
|
resolve(node.children);
|
||||||
}, expandError => {
|
}, expandError => {
|
||||||
|
node.setExpandedState(TreeItemCollapsibleState.Collapsed);
|
||||||
|
node.errorStateMessage = expandError;
|
||||||
this.showError(expandError);
|
this.showError(expandError);
|
||||||
resolve([]);
|
resolve([]);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ export class ServerTreeView {
|
|||||||
|
|
||||||
let expandGroups: boolean = self._configurationService.getValue(SERVER_GROUP_CONFIG)[SERVER_GROUP_AUTOEXPAND_CONFIG];
|
let expandGroups: boolean = self._configurationService.getValue(SERVER_GROUP_CONFIG)[SERVER_GROUP_AUTOEXPAND_CONFIG];
|
||||||
if (expandGroups) {
|
if (expandGroups) {
|
||||||
self._tree.expandAll(ConnectionProfileGroup.getSubgroups(root));
|
self._tree.expandAll(ConnectionProfileGroup.getSubgroups(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root && !root.hasValidConnections) {
|
if (root && !root.hasValidConnections) {
|
||||||
@@ -244,6 +244,10 @@ export class ServerTreeView {
|
|||||||
TreeUpdateUtils.registeredServerUpdate(this._tree, this._connectionManagementService);
|
TreeUpdateUtils.registeredServerUpdate(this._tree, this._connectionManagementService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public refreshElement(element: any): Thenable<void> {
|
||||||
|
return this._tree.refresh(element);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter connections based on view (recent/active)
|
* Filter connections based on view (recent/active)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,6 +10,27 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
|||||||
import { EditorInput } from 'vs/workbench/common/editor';
|
import { EditorInput } from 'vs/workbench/common/editor';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
|
import { GridPanelState } from 'sql/parts/query/editor/gridPanel';
|
||||||
|
import { MessagePanelState } from 'sql/parts/query/editor/messagePanel';
|
||||||
|
import { QueryPlanState } from 'sql/parts/queryPlan/queryPlan';
|
||||||
|
import { ChartState } from 'sql/parts/query/editor/charting/chartView';
|
||||||
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
|
||||||
|
export class ResultsViewState {
|
||||||
|
public gridPanelState: GridPanelState = new GridPanelState();
|
||||||
|
public messagePanelState: MessagePanelState = new MessagePanelState(this.configurationService);
|
||||||
|
public chartState: ChartState = new ChartState();
|
||||||
|
public queryPlanState: QueryPlanState = new QueryPlanState();
|
||||||
|
public gridPanelSize: number;
|
||||||
|
public messagePanelSize: number;
|
||||||
|
public activeTab: string;
|
||||||
|
public visibleTabs: Set<string> = new Set<string>();
|
||||||
|
|
||||||
|
constructor(@IConfigurationService private configurationService: IConfigurationService) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Input for the QueryResultsEditor. This input helps with logic for the viewing and editing of
|
* Input for the QueryResultsEditor. This input helps with logic for the viewing and editing of
|
||||||
* data in the results grid.
|
* data in the results grid.
|
||||||
@@ -29,7 +50,11 @@ export class QueryResultsInput extends EditorInput {
|
|||||||
public readonly onRestoreViewStateEmitter = new Emitter<void>();
|
public readonly onRestoreViewStateEmitter = new Emitter<void>();
|
||||||
public readonly onSaveViewStateEmitter = new Emitter<void>();
|
public readonly onSaveViewStateEmitter = new Emitter<void>();
|
||||||
|
|
||||||
constructor(private _uri: string) {
|
public readonly state = new ResultsViewState(this.configurationService);
|
||||||
|
|
||||||
|
constructor(private _uri: string,
|
||||||
|
@IConfigurationService private configurationService: IConfigurationService
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
this._visible = false;
|
this._visible = false;
|
||||||
this._hasBootstrapped = false;
|
this._hasBootstrapped = false;
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ import { localize } from 'vs/nls';
|
|||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||||
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
|
||||||
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
||||||
import { SaveFormat } from 'sql/parts/grid/common/interfaces';
|
import { SaveFormat } from 'sql/parts/grid/common/interfaces';
|
||||||
import { Table } from 'sql/base/browser/ui/table/table';
|
import { Table } from 'sql/base/browser/ui/table/table';
|
||||||
import { GridTableState } from 'sql/parts/query/editor/gridPanel';
|
import { GridTableState } from 'sql/parts/query/editor/gridPanel';
|
||||||
import { QueryEditor } from './queryEditor';
|
import { QueryEditor } from './queryEditor';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { CellSelectionModel } from 'sql/base/browser/ui/table/plugins/cellSelectionModel.plugin';
|
||||||
|
|
||||||
export interface IGridActionContext {
|
export interface IGridActionContext {
|
||||||
cell: { row: number; cell: number; };
|
cell: { row: number; cell: number; };
|
||||||
@@ -26,6 +27,7 @@ export interface IGridActionContext {
|
|||||||
batchId: number;
|
batchId: number;
|
||||||
resultId: number;
|
resultId: number;
|
||||||
table: Table<any>;
|
table: Table<any>;
|
||||||
|
selectionModel: CellSelectionModel<any>;
|
||||||
tableState: GridTableState;
|
tableState: GridTableState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +115,7 @@ export class SelectAllGridAction extends Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public run(context: IGridActionContext): TPromise<boolean> {
|
public run(context: IGridActionContext): TPromise<boolean> {
|
||||||
context.table.setSelectedRows(true);
|
context.selectionModel.setSelectedRanges([new Slick.Range(0, 0, context.table.getData().getLength() - 1, context.table.columns.length - 1)]);
|
||||||
return TPromise.as(true);
|
return TPromise.as(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,13 +169,13 @@ export class MaximizeTableAction extends Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MinimizeTableAction extends Action {
|
export class RestoreTableAction extends Action {
|
||||||
public static ID = 'grid.minimize';
|
public static ID = 'grid.restore';
|
||||||
public static LABEL = localize('minimize', 'Minimize');
|
public static LABEL = localize('restore', 'Restore');
|
||||||
public static ICON = 'exitFullScreen';
|
public static ICON = 'exitFullScreen';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(MinimizeTableAction.ID, MinimizeTableAction.LABEL, MinimizeTableAction.ICON);
|
super(RestoreTableAction.ID, RestoreTableAction.LABEL, RestoreTableAction.ICON);
|
||||||
}
|
}
|
||||||
|
|
||||||
public run(context: IGridActionContext): TPromise<boolean> {
|
public run(context: IGridActionContext): TPromise<boolean> {
|
||||||
@@ -221,5 +223,4 @@ export class ShowQueryPlanAction extends Action {
|
|||||||
return TPromise.as(false);
|
return TPromise.as(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,10 +8,9 @@
|
|||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
|
||||||
import { ChartType, DataDirection, LegendPosition } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
|
||||||
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/common/insightRegistry';
|
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/common/insightRegistry';
|
||||||
import { DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/types/lineChart.component';
|
|
||||||
import { InsightType, IInsightOptions } from './insights/interfaces';
|
import { InsightType, IInsightOptions } from './insights/interfaces';
|
||||||
|
import { DataDirection, ChartType, LegendPosition, DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
|
|
||||||
const insightRegistry = Registry.as<IInsightRegistry>(Extensions.InsightContribution);
|
const insightRegistry = Registry.as<IInsightRegistry>(Extensions.InsightContribution);
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
|||||||
|
|
||||||
export class ChartTab implements IPanelTab {
|
export class ChartTab implements IPanelTab {
|
||||||
public readonly title = localize('chartTabTitle', 'Chart');
|
public readonly title = localize('chartTabTitle', 'Chart');
|
||||||
public readonly identifier = generateUuid();
|
public readonly identifier = 'ChartTab';
|
||||||
public readonly view: ChartView;
|
public readonly view: ChartView;
|
||||||
|
|
||||||
constructor(@IInstantiationService instantiationService: IInstantiationService) {
|
constructor(@IInstantiationService instantiationService: IInstantiationService) {
|
||||||
|
|||||||
@@ -12,12 +12,13 @@ import { Insight } from './insights/insight';
|
|||||||
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
||||||
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
||||||
import { ChartOptions, IChartOption, ControlType } from './chartOptions';
|
import { ChartOptions, IChartOption, ControlType } from './chartOptions';
|
||||||
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/common/insightRegistry';
|
||||||
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox';
|
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox';
|
||||||
import { IInsightOptions } from './insights/interfaces';
|
import { IInsightOptions } from './insights/interfaces';
|
||||||
import { CopyAction, SaveImageAction, CreateInsightAction, IChartActionContext } from './actions';
|
import { CopyAction, SaveImageAction, CreateInsightAction, IChartActionContext } from './actions';
|
||||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||||
|
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { Dimension, $, getContentHeight, getContentWidth } from 'vs/base/browser/dom';
|
import { Dimension, $, getContentHeight, getContentWidth } from 'vs/base/browser/dom';
|
||||||
import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
|
import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||||
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||||
@@ -27,11 +28,21 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
|||||||
import { attachSelectBoxStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler';
|
import { attachSelectBoxStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler';
|
||||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { isUndefinedOrNull } from 'vs/base/common/types';
|
||||||
|
|
||||||
|
export class ChartState {
|
||||||
|
dataId: { batchId: number, resultId: number };
|
||||||
|
options: IInsightOptions = {
|
||||||
|
type: ChartType.Bar
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
declare class Proxy {
|
declare class Proxy {
|
||||||
constructor(object, handler);
|
constructor(object, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const insightRegistry = Registry.as<IInsightRegistry>(Extensions.InsightContribution);
|
||||||
|
|
||||||
export class ChartView implements IPanelView {
|
export class ChartView implements IPanelView {
|
||||||
private insight: Insight;
|
private insight: Insight;
|
||||||
private _queryRunner: QueryRunner;
|
private _queryRunner: QueryRunner;
|
||||||
@@ -43,6 +54,8 @@ export class ChartView implements IPanelView {
|
|||||||
private _copyAction: CopyAction;
|
private _copyAction: CopyAction;
|
||||||
private _saveAction: SaveImageAction;
|
private _saveAction: SaveImageAction;
|
||||||
|
|
||||||
|
private _state: ChartState;
|
||||||
|
|
||||||
private options: IInsightOptions = {
|
private options: IInsightOptions = {
|
||||||
type: ChartType.Bar
|
type: ChartType.Bar
|
||||||
};
|
};
|
||||||
@@ -61,7 +74,7 @@ export class ChartView implements IPanelView {
|
|||||||
private chartingContainer: HTMLElement;
|
private chartingContainer: HTMLElement;
|
||||||
|
|
||||||
private optionDisposables: IDisposable[] = [];
|
private optionDisposables: IDisposable[] = [];
|
||||||
private optionMap: { [x: string]: HTMLElement } = {};
|
private optionMap: { [x: string]: { element: HTMLElement; set: (val) => void } } = {};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IContextViewService private _contextViewService: IContextViewService,
|
@IContextViewService private _contextViewService: IContextViewService,
|
||||||
@@ -95,6 +108,10 @@ export class ChartView implements IPanelView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let result = Reflect.set(target, key, value, receiver);
|
let result = Reflect.set(target, key, value, receiver);
|
||||||
|
// mirror the change in our state
|
||||||
|
if (self.state) {
|
||||||
|
Reflect.set(self.state.options, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
if (change) {
|
if (change) {
|
||||||
self.taskbar.context = <IChartActionContext>{ options: self.options, insight: self.insight ? self.insight.insight : undefined };
|
self.taskbar.context = <IChartActionContext>{ options: self.options, insight: self.insight ? self.insight.insight : undefined };
|
||||||
@@ -109,6 +126,7 @@ export class ChartView implements IPanelView {
|
|||||||
}
|
}
|
||||||
}) as IInsightOptions;
|
}) as IInsightOptions;
|
||||||
|
|
||||||
|
ChartOptions.general[0].options = insightRegistry.getAllIds();
|
||||||
ChartOptions.general.map(o => {
|
ChartOptions.general.map(o => {
|
||||||
this.createOption(o, generalControls);
|
this.createOption(o, generalControls);
|
||||||
});
|
});
|
||||||
@@ -138,6 +156,7 @@ export class ChartView implements IPanelView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public chart(dataId: { batchId: number, resultId: number }) {
|
public chart(dataId: { batchId: number, resultId: number }) {
|
||||||
|
this.state.dataId = dataId;
|
||||||
this._currentData = dataId;
|
this._currentData = dataId;
|
||||||
this.shouldGraph();
|
this.shouldGraph();
|
||||||
}
|
}
|
||||||
@@ -172,7 +191,7 @@ export class ChartView implements IPanelView {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if we have the necessary information but the information isn't avaiable yet,
|
// if we have the necessary information but the information isn't available yet,
|
||||||
// we should be smart and retrying when the information might be available
|
// we should be smart and retrying when the information might be available
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,7 +199,9 @@ export class ChartView implements IPanelView {
|
|||||||
private buildOptions() {
|
private buildOptions() {
|
||||||
dispose(this.optionDisposables);
|
dispose(this.optionDisposables);
|
||||||
this.optionDisposables = [];
|
this.optionDisposables = [];
|
||||||
this.optionMap = {};
|
this.optionMap = {
|
||||||
|
'type': this.optionMap['type']
|
||||||
|
};
|
||||||
new Builder(this.typeControls).clearChildren();
|
new Builder(this.typeControls).clearChildren();
|
||||||
|
|
||||||
this.updateActionbar();
|
this.updateActionbar();
|
||||||
@@ -200,9 +221,9 @@ export class ChartView implements IPanelView {
|
|||||||
let option = ChartOptions[this.options.type].find(e => e.configEntry === key);
|
let option = ChartOptions[this.options.type].find(e => e.configEntry === key);
|
||||||
if (option && option.if) {
|
if (option && option.if) {
|
||||||
if (option.if(this.options)) {
|
if (option.if(this.options)) {
|
||||||
new Builder(this.optionMap[key]).show();
|
new Builder(this.optionMap[key].element).show();
|
||||||
} else {
|
} else {
|
||||||
new Builder(this.optionMap[key]).hide();
|
new Builder(this.optionMap[key].element).hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,6 +232,7 @@ export class ChartView implements IPanelView {
|
|||||||
|
|
||||||
private updateActionbar() {
|
private updateActionbar() {
|
||||||
if (this.insight && this.insight.isCopyable) {
|
if (this.insight && this.insight.isCopyable) {
|
||||||
|
this.taskbar.context = { insight: this.insight.insight, options: this.options };
|
||||||
this.taskbar.setContent([
|
this.taskbar.setContent([
|
||||||
{ action: this._createInsightAction },
|
{ action: this._createInsightAction },
|
||||||
{ action: this._copyAction },
|
{ action: this._copyAction },
|
||||||
@@ -226,57 +248,104 @@ export class ChartView implements IPanelView {
|
|||||||
label.innerText = option.label;
|
label.innerText = option.label;
|
||||||
let optionContainer = $('div.option-container');
|
let optionContainer = $('div.option-container');
|
||||||
optionContainer.appendChild(label);
|
optionContainer.appendChild(label);
|
||||||
|
let setFunc: (val) => void;
|
||||||
|
let value = this.state ? this.state.options[option.configEntry] || option.default : option.default;
|
||||||
switch (option.type) {
|
switch (option.type) {
|
||||||
case ControlType.checkbox:
|
case ControlType.checkbox:
|
||||||
let checkbox = new Checkbox(optionContainer, {
|
let checkbox = new Checkbox(optionContainer, {
|
||||||
label: '',
|
label: '',
|
||||||
ariaLabel: option.label,
|
ariaLabel: option.label,
|
||||||
checked: option.default,
|
checked: value,
|
||||||
onChange: () => {
|
onChange: () => {
|
||||||
if (this.options[option.configEntry] !== checkbox.checked) {
|
if (this.options[option.configEntry] !== checkbox.checked) {
|
||||||
this.options[option.configEntry] = checkbox.checked;
|
this.options[option.configEntry] = checkbox.checked;
|
||||||
this.insight.options = this.options;
|
if (this.insight) {
|
||||||
|
this.insight.options = this.options;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
setFunc = (val: boolean) => {
|
||||||
|
checkbox.checked = val;
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
case ControlType.combo:
|
case ControlType.combo:
|
||||||
let dropdown = new SelectBox(option.displayableOptions || option.options, 0, this._contextViewService);
|
let dropdown = new SelectBox(option.displayableOptions || option.options, 0, this._contextViewService);
|
||||||
dropdown.select(option.options.indexOf(option.default));
|
dropdown.select(option.options.indexOf(value));
|
||||||
dropdown.render(optionContainer);
|
dropdown.render(optionContainer);
|
||||||
dropdown.onDidSelect(e => {
|
dropdown.onDidSelect(e => {
|
||||||
if (this.options[option.configEntry] !== option.options[e.index]) {
|
if (this.options[option.configEntry] !== option.options[e.index]) {
|
||||||
this.options[option.configEntry] = option.options[e.index];
|
this.options[option.configEntry] = option.options[e.index];
|
||||||
this.insight.options = this.options;
|
if (this.insight) {
|
||||||
|
this.insight.options = this.options;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
setFunc = (val: string) => {
|
||||||
|
if (!isUndefinedOrNull(val)) {
|
||||||
|
dropdown.select(option.options.indexOf(val));
|
||||||
|
}
|
||||||
|
};
|
||||||
this.optionDisposables.push(attachSelectBoxStyler(dropdown, this._themeService));
|
this.optionDisposables.push(attachSelectBoxStyler(dropdown, this._themeService));
|
||||||
break;
|
break;
|
||||||
case ControlType.input:
|
case ControlType.input:
|
||||||
let input = new InputBox(optionContainer, this._contextViewService);
|
let input = new InputBox(optionContainer, this._contextViewService);
|
||||||
input.value = option.default || '';
|
input.value = value || '';
|
||||||
input.onDidChange(e => {
|
input.onDidChange(e => {
|
||||||
if (this.options[option.configEntry] !== e) {
|
if (this.options[option.configEntry] !== e) {
|
||||||
this.options[option.configEntry] = e;
|
this.options[option.configEntry] = e;
|
||||||
this.insight.options = this.options;
|
if (this.insight) {
|
||||||
|
this.insight.options = this.options;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
setFunc = (val: string) => {
|
||||||
|
if (!isUndefinedOrNull(val)) {
|
||||||
|
input.value = val;
|
||||||
|
}
|
||||||
|
};
|
||||||
this.optionDisposables.push(attachInputBoxStyler(input, this._themeService));
|
this.optionDisposables.push(attachInputBoxStyler(input, this._themeService));
|
||||||
break;
|
break;
|
||||||
case ControlType.numberInput:
|
case ControlType.numberInput:
|
||||||
let numberInput = new InputBox(optionContainer, this._contextViewService, { type: 'number' });
|
let numberInput = new InputBox(optionContainer, this._contextViewService, { type: 'number' });
|
||||||
numberInput.value = option.default || '';
|
numberInput.value = value || '';
|
||||||
numberInput.onDidChange(e => {
|
numberInput.onDidChange(e => {
|
||||||
if (this.options[option.configEntry] !== Number(e)) {
|
if (this.options[option.configEntry] !== Number(e)) {
|
||||||
this.options[option.configEntry] = Number(e);
|
this.options[option.configEntry] = Number(e);
|
||||||
this.insight.options = this.options;
|
if (this.insight) {
|
||||||
|
this.insight.options = this.options;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
setFunc = (val: string) => {
|
||||||
|
if (!isUndefinedOrNull(val)) {
|
||||||
|
numberInput.value = val;
|
||||||
|
}
|
||||||
|
};
|
||||||
this.optionDisposables.push(attachInputBoxStyler(numberInput, this._themeService));
|
this.optionDisposables.push(attachInputBoxStyler(numberInput, this._themeService));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.optionMap[option.configEntry] = optionContainer;
|
this.optionMap[option.configEntry] = { element: optionContainer, set: setFunc };
|
||||||
container.appendChild(optionContainer);
|
container.appendChild(optionContainer);
|
||||||
this.options[option.configEntry] = option.default;
|
this.options[option.configEntry] = value;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public set state(val: ChartState) {
|
||||||
|
this._state = val;
|
||||||
|
if (this.state.options) {
|
||||||
|
for (let key in this.state.options) {
|
||||||
|
if (this.state.options.hasOwnProperty(key) && this.optionMap[key]) {
|
||||||
|
this.options[key] = this.state.options[key];
|
||||||
|
this.optionMap[key].set(this.state.options[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.state.dataId) {
|
||||||
|
this.chart(this.state.dataId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get state(): ChartState {
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import * as colors from 'vs/platform/theme/common/colorRegistry';
|
|||||||
import { editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry';
|
import { editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry';
|
||||||
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||||
|
|
||||||
import { ChartType, DataDirection, LegendPosition } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
|
||||||
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
||||||
import { IInsightOptions, IInsight } from './interfaces';
|
import { IInsightOptions, IInsight } from './interfaces';
|
||||||
|
import { ChartType, DataDirection, LegendPosition } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
|
|
||||||
const noneLineGraphs = [ChartType.Doughnut, ChartType.Pie];
|
const noneLineGraphs = [ChartType.Doughnut, ChartType.Pie];
|
||||||
|
|
||||||
@@ -149,6 +149,8 @@ export class Graph implements IInsight {
|
|||||||
let foreground = foregroundColor ? foregroundColor.toString() : null;
|
let foreground = foregroundColor ? foregroundColor.toString() : null;
|
||||||
let gridLinesColor = this._theme.getColor(editorLineNumbers);
|
let gridLinesColor = this._theme.getColor(editorLineNumbers);
|
||||||
let gridLines = gridLinesColor ? gridLinesColor.toString() : null;
|
let gridLines = gridLinesColor ? gridLinesColor.toString() : null;
|
||||||
|
let backgroundColor = this._theme.getColor(colors.editorBackground);
|
||||||
|
let background = backgroundColor ? backgroundColor.toString() : null;
|
||||||
|
|
||||||
if (options) {
|
if (options) {
|
||||||
retval.scales = {};
|
retval.scales = {};
|
||||||
@@ -187,12 +189,20 @@ export class Graph implements IInsight {
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
retval.legend = {
|
retval.legend = <ChartJs.ChartLegendOptions>{
|
||||||
position: options.legendPosition as ChartJs.PositionType,
|
position: options.legendPosition as ChartJs.PositionType,
|
||||||
display: options.legendPosition !== LegendPosition.None
|
display: options.legendPosition !== LegendPosition.None,
|
||||||
|
labels: {
|
||||||
|
fontColor: foreground
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// these are custom options that will throw compile errors
|
||||||
|
(<any>retval).viewArea = {
|
||||||
|
backgroundColor: background
|
||||||
|
};
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,15 +6,15 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { Graph } from './graphInsight';
|
import { Graph } from './graphInsight';
|
||||||
import { ChartType, DataDirection } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
|
||||||
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
||||||
|
import { DataDirection, ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
import { Builder } from 'vs/base/browser/builder';
|
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
|
||||||
import { ImageInsight } from './imageInsight';
|
import { ImageInsight } from './imageInsight';
|
||||||
import { TableInsight } from './tableInsight';
|
import { TableInsight } from './tableInsight';
|
||||||
import { IInsightOptions, IInsight, InsightType, IInsightCtor } from './interfaces';
|
import { IInsightOptions, IInsight, InsightType, IInsightCtor } from './interfaces';
|
||||||
import { CountInsight } from './countInsight';
|
import { CountInsight } from './countInsight';
|
||||||
|
|
||||||
|
import { Builder } from 'vs/base/browser/builder';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { Dimension } from 'vs/base/browser/dom';
|
import { Dimension } from 'vs/base/browser/dom';
|
||||||
|
|
||||||
const defaultOptions: IInsightOptions = {
|
const defaultOptions: IInsightOptions = {
|
||||||
|
|||||||
@@ -4,11 +4,10 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
import { Dimension } from 'vs/base/browser/dom';
|
||||||
|
|
||||||
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
|
||||||
import { ChartType, LegendPosition, DataDirection } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
|
import { DataDirection, ChartType, LegendPosition, DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
|
||||||
import { Dimension } from 'vs/base/browser/dom';
|
|
||||||
import { DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/types/lineChart.component';
|
|
||||||
|
|
||||||
export interface IInsightOptions {
|
export interface IInsightOptions {
|
||||||
type: InsightType | ChartType;
|
type: InsightType | ChartType;
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ import { ScrollableSplitView } from 'sql/base/browser/ui/scrollableSplitview/scr
|
|||||||
import { MouseWheelSupport } from 'sql/base/browser/ui/table/plugins/mousewheelTableScroll.plugin';
|
import { MouseWheelSupport } from 'sql/base/browser/ui/table/plugins/mousewheelTableScroll.plugin';
|
||||||
import { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin';
|
import { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin';
|
||||||
import { SaveFormat } from 'sql/parts/grid/common/interfaces';
|
import { SaveFormat } from 'sql/parts/grid/common/interfaces';
|
||||||
import { IGridActionContext, SaveResultAction, CopyResultAction, SelectAllGridAction, MaximizeTableAction, MinimizeTableAction, ChartDataAction, ShowQueryPlanAction } from 'sql/parts/query/editor/actions';
|
import { IGridActionContext, SaveResultAction, CopyResultAction, SelectAllGridAction, MaximizeTableAction, RestoreTableAction, ChartDataAction, ShowQueryPlanAction } from 'sql/parts/query/editor/actions';
|
||||||
import { CellSelectionModel } from 'sql/base/browser/ui/table/plugins/cellSelectionModel.plugin';
|
import { CellSelectionModel } from 'sql/base/browser/ui/table/plugins/cellSelectionModel.plugin';
|
||||||
import { RowNumberColumn } from 'sql/base/browser/ui/table/plugins/rowNumberColumn.plugin';
|
import { RowNumberColumn } from 'sql/base/browser/ui/table/plugins/rowNumberColumn.plugin';
|
||||||
import { escape } from 'sql/base/common/strings';
|
import { escape } from 'sql/base/common/strings';
|
||||||
import { hyperLinkFormatter, textFormatter } from 'sql/parts/grid/services/sharedServices';
|
import { hyperLinkFormatter, textFormatter } from 'sql/parts/grid/services/sharedServices';
|
||||||
|
import { CopyKeybind } from 'sql/base/browser/ui/table/plugins/copyKeybind.plugin';
|
||||||
|
import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin';
|
||||||
|
|
||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
|
|
||||||
@@ -34,25 +36,30 @@ import { $ } from 'vs/base/browser/builder';
|
|||||||
import { generateUuid } from 'vs/base/common/uuid';
|
import { generateUuid } from 'vs/base/common/uuid';
|
||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { Separator, ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
import { Separator, ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||||
import { Dimension, getContentWidth } from 'vs/base/browser/dom';
|
import { Dimension, getContentWidth, isInDOM } from 'vs/base/browser/dom';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { CopyKeybind } from 'sql/base/browser/ui/table/plugins/copyKeybind.plugin';
|
import { IAction } from 'vs/base/common/actions';
|
||||||
|
|
||||||
const ROW_HEIGHT = 29;
|
const ROW_HEIGHT = 29;
|
||||||
const HEADER_HEIGHT = 26;
|
const HEADER_HEIGHT = 26;
|
||||||
const MIN_GRID_HEIGHT_ROWS = 8;
|
const MIN_GRID_HEIGHT_ROWS = 8;
|
||||||
const ESTIMATED_SCROLL_BAR_HEIGHT = 10;
|
const ESTIMATED_SCROLL_BAR_HEIGHT = 10;
|
||||||
const BOTTOM_PADDING = 5;
|
const BOTTOM_PADDING = 15;
|
||||||
const ACTIONBAR_WIDTH = 26;
|
const ACTIONBAR_WIDTH = 26;
|
||||||
|
|
||||||
// minimum height needed to show the full actionbar
|
// minimum height needed to show the full actionbar
|
||||||
const ACTIONBAR_HEIGHT = 100;
|
const ACTIONBAR_HEIGHT = 100;
|
||||||
|
|
||||||
// this handles min size if rows is greater than the min grid visible rows
|
// this handles min size if rows is greater than the min grid visible rows
|
||||||
const MIN_GRID_HEIGHT = (MIN_GRID_HEIGHT_ROWS * ROW_HEIGHT) + HEADER_HEIGHT + ESTIMATED_SCROLL_BAR_HEIGHT + BOTTOM_PADDING;
|
const MIN_GRID_HEIGHT = (MIN_GRID_HEIGHT_ROWS * ROW_HEIGHT) + HEADER_HEIGHT + ESTIMATED_SCROLL_BAR_HEIGHT;
|
||||||
|
|
||||||
|
export class GridPanelState {
|
||||||
|
public tableStates: GridTableState[] = [];
|
||||||
|
public scrollPosition: number;
|
||||||
|
public collapsed = false;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IGridTableState {
|
export interface IGridTableState {
|
||||||
canBeMaximized: boolean;
|
canBeMaximized: boolean;
|
||||||
@@ -66,13 +73,29 @@ export class GridTableState {
|
|||||||
private _onMaximizedChange = new Emitter<boolean>();
|
private _onMaximizedChange = new Emitter<boolean>();
|
||||||
public onMaximizedChange: Event<boolean> = this._onMaximizedChange.event;
|
public onMaximizedChange: Event<boolean> = this._onMaximizedChange.event;
|
||||||
|
|
||||||
public canBeMaximized: boolean;
|
private _onCanBeMaximizedChange = new Emitter<boolean>();
|
||||||
|
public onCanBeMaximizedChange: Event<boolean> = this._onCanBeMaximizedChange.event;
|
||||||
|
|
||||||
constructor(state?: IGridTableState) {
|
private _canBeMaximized: boolean;
|
||||||
if (state) {
|
|
||||||
this._maximized = state.maximized;
|
/* The top row of the current scroll */
|
||||||
this.canBeMaximized = state.canBeMaximized;
|
public scrollPosition = 0;
|
||||||
|
public selection: Slick.Range[];
|
||||||
|
public activeCell: Slick.Cell;
|
||||||
|
|
||||||
|
constructor(public readonly resultId: number, public readonly batchId: number) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public get canBeMaximized(): boolean {
|
||||||
|
return this._canBeMaximized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set canBeMaximized(val: boolean) {
|
||||||
|
if (val === this._canBeMaximized) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
this._canBeMaximized = val;
|
||||||
|
this._onCanBeMaximizedChange.fire(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get maximized(): boolean {
|
public get maximized(): boolean {
|
||||||
@@ -86,10 +109,6 @@ export class GridTableState {
|
|||||||
this._maximized = val;
|
this._maximized = val;
|
||||||
this._onMaximizedChange.fire(val);
|
this._onMaximizedChange.fire(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public clone(): GridTableState {
|
|
||||||
return new GridTableState({ canBeMaximized: this.canBeMaximized, maximized: this.maximized });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GridPanel extends ViewletPanel {
|
export class GridPanel extends ViewletPanel {
|
||||||
@@ -103,6 +122,7 @@ export class GridPanel extends ViewletPanel {
|
|||||||
private runner: QueryRunner;
|
private runner: QueryRunner;
|
||||||
|
|
||||||
private maximizedGrid: GridTable<any>;
|
private maximizedGrid: GridTable<any>;
|
||||||
|
private _state: GridPanelState;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
options: IViewletPanelOptions,
|
options: IViewletPanelOptions,
|
||||||
@@ -114,6 +134,16 @@ export class GridPanel extends ViewletPanel {
|
|||||||
) {
|
) {
|
||||||
super(options, keybindingService, contextMenuService, configurationService);
|
super(options, keybindingService, contextMenuService, configurationService);
|
||||||
this.splitView = new ScrollableSplitView(this.container, { enableResizing: false });
|
this.splitView = new ScrollableSplitView(this.container, { enableResizing: false });
|
||||||
|
this.splitView.onScroll(e => {
|
||||||
|
if (this.state) {
|
||||||
|
this.state.scrollPosition = e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.onDidChange(e => {
|
||||||
|
if (this.state) {
|
||||||
|
this.state.collapsed = !this.isExpanded();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderBody(container: HTMLElement): void {
|
protected renderBody(container: HTMLElement): void {
|
||||||
@@ -138,7 +168,12 @@ export class GridPanel extends ViewletPanel {
|
|||||||
this.queryRunnerDisposables = [];
|
this.queryRunnerDisposables = [];
|
||||||
this.runner = runner;
|
this.runner = runner;
|
||||||
this.queryRunnerDisposables.push(this.runner.onResultSet(e => this.onResultSet(e)));
|
this.queryRunnerDisposables.push(this.runner.onResultSet(e => this.onResultSet(e)));
|
||||||
this.queryRunnerDisposables.push(this.runner.onQueryStart(() => this.reset()));
|
this.queryRunnerDisposables.push(this.runner.onQueryStart(() => {
|
||||||
|
if (this.state) {
|
||||||
|
this.state.tableStates = [];
|
||||||
|
}
|
||||||
|
this.reset();
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private onResultSet(resultSet: sqlops.ResultSetSummary | sqlops.ResultSetSummary[]) {
|
private onResultSet(resultSet: sqlops.ResultSetSummary | sqlops.ResultSetSummary[]) {
|
||||||
@@ -151,6 +186,10 @@ export class GridPanel extends ViewletPanel {
|
|||||||
this.maximumBodySize = this.tables.reduce((p, c) => {
|
this.maximumBodySize = this.tables.reduce((p, c) => {
|
||||||
return p + c.maximumSize;
|
return p + c.maximumSize;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
|
if (this.state && this.state.scrollPosition) {
|
||||||
|
this.splitView.setScrollPosition(this.state.scrollPosition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private addResultSet(resultSet: sqlops.ResultSetSummary | sqlops.ResultSetSummary[]) {
|
private addResultSet(resultSet: sqlops.ResultSetSummary | sqlops.ResultSetSummary[]) {
|
||||||
@@ -164,8 +203,18 @@ export class GridPanel extends ViewletPanel {
|
|||||||
let tables: GridTable<any>[] = [];
|
let tables: GridTable<any>[] = [];
|
||||||
|
|
||||||
for (let set of resultsToAdd) {
|
for (let set of resultsToAdd) {
|
||||||
let tableState = new GridTableState();
|
let tableState: GridTableState;
|
||||||
let table = this.instantiationService.createInstance(GridTable, this.runner, tableState, set);
|
if (this._state) {
|
||||||
|
tableState = this.state.tableStates.find(e => e.batchId === set.batchId && e.resultId === set.id);
|
||||||
|
}
|
||||||
|
if (!tableState) {
|
||||||
|
tableState = new GridTableState(set.id, set.batchId);
|
||||||
|
if (this._state) {
|
||||||
|
this._state.tableStates.push(tableState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let table = this.instantiationService.createInstance(GridTable, this.runner, set);
|
||||||
|
table.state = tableState;
|
||||||
tableState.onMaximizedChange(e => {
|
tableState.onMaximizedChange(e => {
|
||||||
if (e) {
|
if (e) {
|
||||||
this.maximizeTable(table.id);
|
this.maximizeTable(table.id);
|
||||||
@@ -191,7 +240,6 @@ export class GridPanel extends ViewletPanel {
|
|||||||
for (let i = this.splitView.length - 1; i >= 0; i--) {
|
for (let i = this.splitView.length - 1; i >= 0; i--) {
|
||||||
this.splitView.removeView(i);
|
this.splitView.removeView(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose(this.tables);
|
dispose(this.tables);
|
||||||
this.tables = [];
|
this.tables = [];
|
||||||
|
|
||||||
@@ -224,6 +272,24 @@ export class GridPanel extends ViewletPanel {
|
|||||||
this.splitView.addViews(this.tables, this.tables.map(i => i.minimumSize));
|
this.splitView.addViews(this.tables, this.tables.map(i => i.minimumSize));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public set state(val: GridPanelState) {
|
||||||
|
this._state = val;
|
||||||
|
this.tables.map(t => {
|
||||||
|
let state = this.state.tableStates.find(s => s.batchId === t.resultSet.batchId && s.resultId === t.resultSet.id);
|
||||||
|
if (!state) {
|
||||||
|
this.state.tableStates.push(t.state);
|
||||||
|
}
|
||||||
|
if (state) {
|
||||||
|
t.state = state;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.setExpanded(!this.state.collapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get state(): GridPanelState {
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GridTable<T> extends Disposable implements IView {
|
class GridTable<T> extends Disposable implements IView {
|
||||||
@@ -242,13 +308,16 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
public id = generateUuid();
|
public id = generateUuid();
|
||||||
readonly element: HTMLElement = this.container;
|
readonly element: HTMLElement = this.container;
|
||||||
|
|
||||||
|
private _state: GridTableState;
|
||||||
|
|
||||||
|
private scrolled = false;
|
||||||
|
|
||||||
// this handles if the row count is small, like 4-5 rows
|
// this handles if the row count is small, like 4-5 rows
|
||||||
private readonly maxSize = ((this.resultSet.rowCount) * ROW_HEIGHT) + HEADER_HEIGHT + ESTIMATED_SCROLL_BAR_HEIGHT + BOTTOM_PADDING;
|
private readonly maxSize = ((this.resultSet.rowCount) * ROW_HEIGHT) + HEADER_HEIGHT + ESTIMATED_SCROLL_BAR_HEIGHT;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private runner: QueryRunner,
|
private runner: QueryRunner,
|
||||||
public state: GridTableState,
|
public readonly resultSet: sqlops.ResultSetSummary,
|
||||||
private resultSet: sqlops.ResultSetSummary,
|
|
||||||
@IContextMenuService private contextMenuService: IContextMenuService,
|
@IContextMenuService private contextMenuService: IContextMenuService,
|
||||||
@IInstantiationService private instantiationService: IInstantiationService,
|
@IInstantiationService private instantiationService: IInstantiationService,
|
||||||
@IEditorService private editorService: IEditorService,
|
@IEditorService private editorService: IEditorService,
|
||||||
@@ -257,7 +326,7 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
super();
|
super();
|
||||||
this.container.style.width = '100%';
|
this.container.style.width = '100%';
|
||||||
this.container.style.height = '100%';
|
this.container.style.height = '100%';
|
||||||
this.container.style.marginBottom = BOTTOM_PADDING + 'px';
|
// this.container.style.marginBottom = BOTTOM_PADDING + 'px';
|
||||||
this.container.className = 'grid-panel';
|
this.container.className = 'grid-panel';
|
||||||
|
|
||||||
this.columns = this.resultSet.columnInfo.map((c, i) => {
|
this.columns = this.resultSet.columnInfo.map((c, i) => {
|
||||||
@@ -274,6 +343,11 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onRemove() {
|
||||||
|
// when we are removed slickgrid acts badly so we need to account for that
|
||||||
|
this.scrolled = false;
|
||||||
|
}
|
||||||
|
|
||||||
public render(container: HTMLElement, orientation: Orientation): void {
|
public render(container: HTMLElement, orientation: Orientation): void {
|
||||||
container.appendChild(this.container);
|
container.appendChild(this.container);
|
||||||
}
|
}
|
||||||
@@ -294,15 +368,7 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
let numberColumn = new RowNumberColumn({ numberOfRows: this.resultSet.rowCount });
|
let numberColumn = new RowNumberColumn({ numberOfRows: this.resultSet.rowCount });
|
||||||
let copyHandler = new CopyKeybind();
|
let copyHandler = new CopyKeybind();
|
||||||
copyHandler.onCopy(e => {
|
copyHandler.onCopy(e => {
|
||||||
new CopyResultAction(CopyResultAction.COPY_ID, CopyResultAction.COPY_LABEL, false).run({
|
new CopyResultAction(CopyResultAction.COPY_ID, CopyResultAction.COPY_LABEL, false).run(this.generateContext());
|
||||||
selection: e,
|
|
||||||
batchId: this.resultSet.batchId,
|
|
||||||
resultId: this.resultSet.id,
|
|
||||||
cell: this.table.grid.getActiveCell(),
|
|
||||||
runner: this.runner,
|
|
||||||
table: this.table,
|
|
||||||
tableState: this.state
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
this.columns.unshift(numberColumn.getColumnDefinition());
|
this.columns.unshift(numberColumn.getColumnDefinition());
|
||||||
let tableOptions: Slick.GridOptions<T> = {
|
let tableOptions: Slick.GridOptions<T> = {
|
||||||
@@ -317,6 +383,7 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
this.table.registerPlugin(new AutoColumnSize());
|
this.table.registerPlugin(new AutoColumnSize());
|
||||||
this.table.registerPlugin(copyHandler);
|
this.table.registerPlugin(copyHandler);
|
||||||
this.table.registerPlugin(numberColumn);
|
this.table.registerPlugin(numberColumn);
|
||||||
|
this.table.registerPlugin(new AdditionalKeyBindings());
|
||||||
this._register(this.table.onContextMenu(this.contextMenu, this));
|
this._register(this.table.onContextMenu(this.contextMenu, this));
|
||||||
this._register(this.table.onClick(this.onTableClick, this));
|
this._register(this.table.onClick(this.onTableClick, this));
|
||||||
|
|
||||||
@@ -324,22 +391,7 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
this.table.style(this.styles);
|
this.table.style(this.styles);
|
||||||
}
|
}
|
||||||
|
|
||||||
let actions = [];
|
let actions = this.getCurrentActions();
|
||||||
|
|
||||||
if (this.state.canBeMaximized) {
|
|
||||||
if (this.state.maximized) {
|
|
||||||
actions.splice(1, 0, new MinimizeTableAction());
|
|
||||||
} else {
|
|
||||||
actions.splice(1, 0, new MaximizeTableAction());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
actions.push(
|
|
||||||
new SaveResultAction(SaveResultAction.SAVECSV_ID, SaveResultAction.SAVECSV_LABEL, SaveResultAction.SAVECSV_ICON, SaveFormat.CSV),
|
|
||||||
new SaveResultAction(SaveResultAction.SAVEEXCEL_ID, SaveResultAction.SAVEEXCEL_LABEL, SaveResultAction.SAVEEXCEL_ICON, SaveFormat.EXCEL),
|
|
||||||
new SaveResultAction(SaveResultAction.SAVEJSON_ID, SaveResultAction.SAVEJSON_LABEL, SaveResultAction.SAVEJSON_ICON, SaveFormat.JSON),
|
|
||||||
this.instantiationService.createInstance(ChartDataAction)
|
|
||||||
);
|
|
||||||
|
|
||||||
let actionBarContainer = document.createElement('div');
|
let actionBarContainer = document.createElement('div');
|
||||||
actionBarContainer.style.width = ACTIONBAR_WIDTH + 'px';
|
actionBarContainer.style.width = ACTIONBAR_WIDTH + 'px';
|
||||||
@@ -356,7 +408,65 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
tableState: this.state
|
tableState: this.state
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// update context before we run an action
|
||||||
|
this.selectionModel.onSelectedRangesChanged.subscribe(e => {
|
||||||
|
this.actionBar.context = this.generateContext();
|
||||||
|
});
|
||||||
this.actionBar.push(actions, { icon: true, label: false });
|
this.actionBar.push(actions, { icon: true, label: false });
|
||||||
|
|
||||||
|
this.selectionModel.onSelectedRangesChanged.subscribe(e => {
|
||||||
|
if (this.state) {
|
||||||
|
this.state.selection = this.selectionModel.getSelectedRanges();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.table.grid.onScroll.subscribe((e, data) => {
|
||||||
|
if (!this.scrolled && this.state.scrollPosition && isInDOM(this.container)) {
|
||||||
|
this.scrolled = true;
|
||||||
|
this.table.grid.scrollTo(this.state.scrollPosition);
|
||||||
|
}
|
||||||
|
if (this.state && isInDOM(this.container)) {
|
||||||
|
this.state.scrollPosition = data.scrollTop;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.table.grid.onActiveCellChanged.subscribe(e => {
|
||||||
|
if (this.state) {
|
||||||
|
this.state.activeCell = this.table.grid.getActiveCell();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setupState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupState() {
|
||||||
|
// change actionbar on maximize change
|
||||||
|
this.state.onMaximizedChange(this.rebuildActionBar, this);
|
||||||
|
|
||||||
|
this.state.onCanBeMaximizedChange(this.rebuildActionBar, this);
|
||||||
|
|
||||||
|
if (this.state.scrollPosition) {
|
||||||
|
// most of the time this won't do anything
|
||||||
|
this.table.grid.scrollTo(this.state.scrollPosition);
|
||||||
|
// the problem here is that the scrolling state slickgrid uses
|
||||||
|
// doesn't work with it offDOM.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.selection) {
|
||||||
|
this.selectionModel.setSelectedRanges(this.state.selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.activeCell) {
|
||||||
|
this.table.setActiveCell(this.state.activeCell.row, this.state.activeCell.cell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get state(): GridTableState {
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set state(val: GridTableState) {
|
||||||
|
this._state = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onTableClick(event: ITableMouseEvent) {
|
private onTableClick(event: ITableMouseEvent) {
|
||||||
@@ -372,6 +482,48 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private generateContext(cell?: Slick.Cell): IGridActionContext {
|
||||||
|
const selection = this.selectionModel.getSelectedRanges();
|
||||||
|
return <IGridActionContext>{
|
||||||
|
cell,
|
||||||
|
selection,
|
||||||
|
runner: this.runner,
|
||||||
|
batchId: this.resultSet.batchId,
|
||||||
|
resultId: this.resultSet.id,
|
||||||
|
table: this.table,
|
||||||
|
tableState: this.state,
|
||||||
|
selectionModel: this.selectionModel
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private rebuildActionBar() {
|
||||||
|
let actions = this.getCurrentActions();
|
||||||
|
this.actionBar.clear();
|
||||||
|
this.actionBar.push(actions, { icon: true, label: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCurrentActions(): IAction[] {
|
||||||
|
|
||||||
|
let actions = [];
|
||||||
|
|
||||||
|
if (this.state.canBeMaximized) {
|
||||||
|
if (this.state.maximized) {
|
||||||
|
actions.splice(1, 0, new RestoreTableAction());
|
||||||
|
} else {
|
||||||
|
actions.splice(1, 0, new MaximizeTableAction());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actions.push(
|
||||||
|
new SaveResultAction(SaveResultAction.SAVECSV_ID, SaveResultAction.SAVECSV_LABEL, SaveResultAction.SAVECSV_ICON, SaveFormat.CSV),
|
||||||
|
new SaveResultAction(SaveResultAction.SAVEEXCEL_ID, SaveResultAction.SAVEEXCEL_LABEL, SaveResultAction.SAVEEXCEL_ICON, SaveFormat.EXCEL),
|
||||||
|
new SaveResultAction(SaveResultAction.SAVEJSON_ID, SaveResultAction.SAVEJSON_LABEL, SaveResultAction.SAVEJSON_ICON, SaveFormat.JSON),
|
||||||
|
this.instantiationService.createInstance(ChartDataAction)
|
||||||
|
);
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
public layout(size?: number): void {
|
public layout(size?: number): void {
|
||||||
if (!this.table) {
|
if (!this.table) {
|
||||||
this.build();
|
this.build();
|
||||||
@@ -384,24 +536,27 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
this.table.layout(
|
this.table.layout(
|
||||||
new Dimension(
|
new Dimension(
|
||||||
getContentWidth(this.container) - ACTIONBAR_WIDTH,
|
getContentWidth(this.container) - ACTIONBAR_WIDTH,
|
||||||
size - BOTTOM_PADDING
|
size
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get minimumSize(): number {
|
public get minimumSize(): number {
|
||||||
// clamp between ensuring we can show the actionbar, while also making sure we don't take too much space
|
// clamp between ensuring we can show the actionbar, while also making sure we don't take too much space
|
||||||
return Math.max(Math.min(this.maxSize, MIN_GRID_HEIGHT), ACTIONBAR_HEIGHT);
|
return Math.max(Math.min(this.maxSize, MIN_GRID_HEIGHT), ACTIONBAR_HEIGHT + BOTTOM_PADDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get maximumSize(): number {
|
public get maximumSize(): number {
|
||||||
return Math.max(this.maxSize, ACTIONBAR_HEIGHT);
|
return Math.max(this.maxSize, ACTIONBAR_HEIGHT + BOTTOM_PADDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadData(offset: number, count: number): Thenable<T[]> {
|
private loadData(offset: number, count: number): Thenable<T[]> {
|
||||||
return this.runner.getQueryRows(offset, count, this.resultSet.batchId, this.resultSet.id).then(response => {
|
return this.runner.getQueryRows(offset, count, this.resultSet.batchId, this.resultSet.id).then(response => {
|
||||||
if (this.runner.isQueryPlan) {
|
if (this.runner.isQueryPlan) {
|
||||||
this.instantiationService.createInstance(ShowQueryPlanAction).run(response.resultSubset.rows[0][0].displayValue);
|
// it's a show plan response
|
||||||
|
if (response.resultSubset.rowCount === 1) {
|
||||||
|
this.instantiationService.createInstance(ShowQueryPlanAction).run(response.resultSubset.rows[0][0].displayValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return response.resultSubset.rows.map(r => {
|
return response.resultSubset.rows.map(r => {
|
||||||
let dataWithSchema = {};
|
let dataWithSchema = {};
|
||||||
@@ -419,7 +574,6 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private contextMenu(e: ITableMouseEvent): void {
|
private contextMenu(e: ITableMouseEvent): void {
|
||||||
const selection = this.selectionModel.getSelectedRanges();
|
|
||||||
const { cell } = e;
|
const { cell } = e;
|
||||||
this.contextMenuService.showContextMenu({
|
this.contextMenuService.showContextMenu({
|
||||||
getAnchor: () => e.anchor,
|
getAnchor: () => e.anchor,
|
||||||
@@ -437,7 +591,7 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
|
|
||||||
if (this.state.canBeMaximized) {
|
if (this.state.canBeMaximized) {
|
||||||
if (this.state.maximized) {
|
if (this.state.maximized) {
|
||||||
actions.splice(1, 0, new MinimizeTableAction());
|
actions.splice(1, 0, new RestoreTableAction());
|
||||||
} else {
|
} else {
|
||||||
actions.splice(1, 0, new MaximizeTableAction());
|
actions.splice(1, 0, new MaximizeTableAction());
|
||||||
}
|
}
|
||||||
@@ -446,15 +600,7 @@ class GridTable<T> extends Disposable implements IView {
|
|||||||
return TPromise.as(actions);
|
return TPromise.as(actions);
|
||||||
},
|
},
|
||||||
getActionsContext: () => {
|
getActionsContext: () => {
|
||||||
return <IGridActionContext>{
|
return this.generateContext(cell);
|
||||||
cell,
|
|
||||||
selection,
|
|
||||||
runner: this.runner,
|
|
||||||
batchId: this.resultSet.batchId,
|
|
||||||
resultId: this.resultSet.id,
|
|
||||||
table: this.table,
|
|
||||||
tableState: this.state
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,18 +13,28 @@
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.monaco-workbench .message-tree .monaco-tree .monaco-tree-rows>.monaco-tree-row {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
.message-tree .time-stamp {
|
.message-tree .time-stamp {
|
||||||
width: 100px;
|
width: 100px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-tree .message,
|
.message-tree .message,
|
||||||
.message-tree .batch-start {
|
.message-tree .batch-start,
|
||||||
|
.message-tree .error-message {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-tree .batch-start {
|
.message-tree .batch-start {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-tree .error-message {
|
||||||
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-tree .batch-start:hover {
|
.message-tree .batch-start:hover {
|
||||||
|
|||||||
5
src/sql/parts/query/editor/media/queryActions.css
Normal file
5
src/sql/parts/query/editor/media/queryActions.css
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.monaco-select-box {
|
||||||
|
cursor: pointer;
|
||||||
|
min-width: 150px;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ import 'vs/css!./media/messagePanel';
|
|||||||
import { IMessagesActionContext, SelectAllMessagesAction, CopyMessagesAction } from './actions';
|
import { IMessagesActionContext, SelectAllMessagesAction, CopyMessagesAction } from './actions';
|
||||||
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
||||||
|
|
||||||
import { IResultMessage, BatchSummary, ISelectionData } from 'sqlops';
|
import { IResultMessage, ISelectionData } from 'sqlops';
|
||||||
|
|
||||||
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
|
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||||
import { IDataSource, ITree, IRenderer, ContextMenuEvent } from 'vs/base/parts/tree/browser/tree';
|
import { IDataSource, ITree, IRenderer, ContextMenuEvent } from 'vs/base/parts/tree/browser/tree';
|
||||||
@@ -25,11 +25,11 @@ import { OpenMode, ClickBehavior, ICancelableEvent, IControllerOptions } from 'v
|
|||||||
import { WorkbenchTreeController } from 'vs/platform/list/browser/listService';
|
import { WorkbenchTreeController } from 'vs/platform/list/browser/listService';
|
||||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||||
import { $ } from 'vs/base/browser/builder';
|
import { $ } from 'vs/base/browser/builder';
|
||||||
import { isArray } from 'vs/base/common/types';
|
import { isArray, isUndefinedOrNull } from 'vs/base/common/types';
|
||||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
import { localize } from 'vs/nls';
|
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { IEditor } from 'vs/editor/common/editorCommon';
|
import { IEditor } from 'vs/editor/common/editorCommon';
|
||||||
|
import { QueryInput } from 'sql/parts/query/common/queryInput';
|
||||||
|
|
||||||
export interface IResultMessageIntern extends IResultMessage {
|
export interface IResultMessageIntern extends IResultMessage {
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -56,9 +56,22 @@ interface IBatchTemplate extends IMessageTemplate {
|
|||||||
const TemplateIds = {
|
const TemplateIds = {
|
||||||
MESSAGE: 'message',
|
MESSAGE: 'message',
|
||||||
BATCH: 'batch',
|
BATCH: 'batch',
|
||||||
MODEL: 'model'
|
MODEL: 'model',
|
||||||
|
ERROR: 'error'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export class MessagePanelState {
|
||||||
|
public scrollPosition: number;
|
||||||
|
public collapsed = false;
|
||||||
|
|
||||||
|
constructor(@IConfigurationService configurationService: IConfigurationService) {
|
||||||
|
let messagesOpenedSettings = configurationService.getValue<boolean>('sql.messagesDefaultOpen');
|
||||||
|
if (!isUndefinedOrNull(messagesOpenedSettings)) {
|
||||||
|
this.collapsed = !messagesOpenedSettings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class MessagePanel extends ViewletPanel {
|
export class MessagePanel extends ViewletPanel {
|
||||||
private ds = new MessageDataSource();
|
private ds = new MessageDataSource();
|
||||||
private renderer = new MessageRenderer();
|
private renderer = new MessageRenderer();
|
||||||
@@ -67,6 +80,7 @@ export class MessagePanel extends ViewletPanel {
|
|||||||
private container = $('div message-tree').getHTMLElement();
|
private container = $('div message-tree').getHTMLElement();
|
||||||
|
|
||||||
private queryRunnerDisposables: IDisposable[] = [];
|
private queryRunnerDisposables: IDisposable[] = [];
|
||||||
|
private _state: MessagePanelState;
|
||||||
|
|
||||||
private tree: ITree;
|
private tree: ITree;
|
||||||
|
|
||||||
@@ -86,6 +100,16 @@ export class MessagePanel extends ViewletPanel {
|
|||||||
renderer: this.renderer,
|
renderer: this.renderer,
|
||||||
controller: this.controller
|
controller: this.controller
|
||||||
}, { keyboardSupport: false });
|
}, { keyboardSupport: false });
|
||||||
|
this.tree.onDidScroll(e => {
|
||||||
|
if (this.state) {
|
||||||
|
this.state.scrollPosition = this.tree.getScrollPosition();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.onDidChange(e => {
|
||||||
|
if (this.state) {
|
||||||
|
this.state.collapsed = !this.isExpanded();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderBody(container: HTMLElement): void {
|
protected renderBody(container: HTMLElement): void {
|
||||||
@@ -99,8 +123,12 @@ export class MessagePanel extends ViewletPanel {
|
|||||||
protected layoutBody(size: number): void {
|
protected layoutBody(size: number): void {
|
||||||
const previousScrollPosition = this.tree.getScrollPosition();
|
const previousScrollPosition = this.tree.getScrollPosition();
|
||||||
this.tree.layout(size);
|
this.tree.layout(size);
|
||||||
if (previousScrollPosition === 1) {
|
if (this.state && this.state.scrollPosition) {
|
||||||
this.tree.setScrollPosition(1);
|
this.tree.setScrollPosition(this.state.scrollPosition);
|
||||||
|
} else {
|
||||||
|
if (previousScrollPosition === 1) {
|
||||||
|
this.tree.setScrollPosition(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,17 +141,30 @@ export class MessagePanel extends ViewletPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onMessage(message: IResultMessage | IResultMessage[]) {
|
private onMessage(message: IResultMessage | IResultMessage[]) {
|
||||||
|
let hasError = false;
|
||||||
if (isArray(message)) {
|
if (isArray(message)) {
|
||||||
|
hasError = message.find(e => e.isError) ? true : false;
|
||||||
this.model.messages.push(...message);
|
this.model.messages.push(...message);
|
||||||
} else {
|
} else {
|
||||||
|
hasError = message.isError;
|
||||||
this.model.messages.push(message);
|
this.model.messages.push(message);
|
||||||
}
|
}
|
||||||
const previousScrollPosition = this.tree.getScrollPosition();
|
if (hasError) {
|
||||||
this.tree.refresh(this.model).then(() => {
|
this.setExpanded(true);
|
||||||
if (previousScrollPosition === 1) {
|
}
|
||||||
|
if (this.state.scrollPosition) {
|
||||||
|
this.tree.refresh(this.model).then(() => {
|
||||||
this.tree.setScrollPosition(1);
|
this.tree.setScrollPosition(1);
|
||||||
}
|
});
|
||||||
});
|
} else {
|
||||||
|
const previousScrollPosition = this.tree.getScrollPosition();
|
||||||
|
this.tree.refresh(this.model).then(() => {
|
||||||
|
if (previousScrollPosition === 1) {
|
||||||
|
this.tree.setScrollPosition(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.maximumBodySize = this.model.messages.length * 22;
|
||||||
}
|
}
|
||||||
|
|
||||||
private reset() {
|
private reset() {
|
||||||
@@ -131,6 +172,17 @@ export class MessagePanel extends ViewletPanel {
|
|||||||
this.model.totalExecuteMessage = undefined;
|
this.model.totalExecuteMessage = undefined;
|
||||||
this.tree.refresh(this.model);
|
this.tree.refresh(this.model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public set state(val: MessagePanelState) {
|
||||||
|
this._state = val;
|
||||||
|
if (this.state.scrollPosition) {
|
||||||
|
this.tree.setScrollPosition(this.state.scrollPosition);
|
||||||
|
}
|
||||||
|
this.setExpanded(!this.state.collapsed);
|
||||||
|
}
|
||||||
|
public get state(): MessagePanelState {
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageDataSource implements IDataSource {
|
class MessageDataSource implements IDataSource {
|
||||||
@@ -176,6 +228,8 @@ class MessageRenderer implements IRenderer {
|
|||||||
return TemplateIds.MODEL;
|
return TemplateIds.MODEL;
|
||||||
} else if (element.selection) {
|
} else if (element.selection) {
|
||||||
return TemplateIds.BATCH;
|
return TemplateIds.BATCH;
|
||||||
|
} else if (element.isError) {
|
||||||
|
return TemplateIds.ERROR;
|
||||||
} else {
|
} else {
|
||||||
return TemplateIds.MESSAGE;
|
return TemplateIds.MESSAGE;
|
||||||
}
|
}
|
||||||
@@ -191,15 +245,19 @@ class MessageRenderer implements IRenderer {
|
|||||||
const timeStamp = $('div.time-stamp').appendTo(container).getHTMLElement();
|
const timeStamp = $('div.time-stamp').appendTo(container).getHTMLElement();
|
||||||
const message = $('div.batch-start').appendTo(container).getHTMLElement();
|
const message = $('div.batch-start').appendTo(container).getHTMLElement();
|
||||||
return { message, timeStamp };
|
return { message, timeStamp };
|
||||||
|
} else if (templateId === TemplateIds.ERROR) {
|
||||||
|
$('div.time-stamp').appendTo(container);
|
||||||
|
const message = $('div.error-message').appendTo(container).getHTMLElement();
|
||||||
|
return { message };
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderElement(tree: ITree, element: IResultMessage, templateId: string, templateData: IMessageTemplate | IBatchTemplate): void {
|
renderElement(tree: ITree, element: IResultMessage, templateId: string, templateData: IMessageTemplate | IBatchTemplate): void {
|
||||||
if (templateId === TemplateIds.MESSAGE) {
|
if (templateId === TemplateIds.MESSAGE || templateId === TemplateIds.ERROR) {
|
||||||
let data: IMessageTemplate = templateData;
|
let data: IMessageTemplate = templateData;
|
||||||
data.message.innerText = element.message;
|
data.message.innerText = element.message.replace(/(\r\n|\n|\r)/g, ' ');
|
||||||
} else if (templateId === TemplateIds.BATCH) {
|
} else if (templateId === TemplateIds.BATCH) {
|
||||||
let data = templateData as IBatchTemplate;
|
let data = templateData as IBatchTemplate;
|
||||||
data.timeStamp.innerText = element.time;
|
data.timeStamp.innerText = element.time;
|
||||||
@@ -245,14 +303,8 @@ export class MessageController extends WorkbenchTreeController {
|
|||||||
if (element.selection) {
|
if (element.selection) {
|
||||||
let selection: ISelectionData = element.selection;
|
let selection: ISelectionData = element.selection;
|
||||||
// this is a batch statement
|
// this is a batch statement
|
||||||
let control = this.workbenchEditorService.activeControl.getControl() as IEditor;
|
let input = this.workbenchEditorService.activeEditor as QueryInput;
|
||||||
control.setSelection({
|
input.updateSelection(selection);
|
||||||
startColumn: selection.startColumn + 1,
|
|
||||||
endColumn: selection.endColumn + 1,
|
|
||||||
endLineNumber: selection.endLine + 1,
|
|
||||||
startLineNumber: selection.startLine + 1
|
|
||||||
});
|
|
||||||
control.focus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ import {
|
|||||||
import { IQueryModelService } from 'sql/parts/query/execution/queryModel';
|
import { IQueryModelService } from 'sql/parts/query/execution/queryModel';
|
||||||
import { IEditorDescriptorService } from 'sql/parts/query/editor/editorDescriptorService';
|
import { IEditorDescriptorService } from 'sql/parts/query/editor/editorDescriptorService';
|
||||||
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
|
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
|
||||||
import { attachEditableDropdownStyler } from 'sql/common/theme/styler';
|
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||||
@@ -378,6 +377,26 @@ export class QueryEditor extends BaseEditor {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getAllSelection(): ISelectionData {
|
||||||
|
if (this._sqlEditor && this._sqlEditor.getControl()) {
|
||||||
|
let control = this._sqlEditor.getControl();
|
||||||
|
let codeEditor: ICodeEditor = <ICodeEditor>control;
|
||||||
|
if (codeEditor) {
|
||||||
|
let model = codeEditor.getModel();
|
||||||
|
let totalLines = model.getLineCount();
|
||||||
|
let endColumn = model.getLineMaxColumn(totalLines);
|
||||||
|
let selection: ISelectionData = {
|
||||||
|
startLine: 0,
|
||||||
|
startColumn: 0,
|
||||||
|
endLine: totalLines - 1,
|
||||||
|
endColumn: endColumn - 1,
|
||||||
|
};
|
||||||
|
return selection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
public getSelectionText(): string {
|
public getSelectionText(): string {
|
||||||
if (this._sqlEditor && this._sqlEditor.getControl()) {
|
if (this._sqlEditor && this._sqlEditor.getControl()) {
|
||||||
let control = this._sqlEditor.getControl();
|
let control = this._sqlEditor.getControl();
|
||||||
@@ -500,7 +519,7 @@ export class QueryEditor extends BaseEditor {
|
|||||||
public get listDatabasesActionItem(): ListDatabasesActionItem {
|
public get listDatabasesActionItem(): ListDatabasesActionItem {
|
||||||
if (!this._listDatabasesActionItem) {
|
if (!this._listDatabasesActionItem) {
|
||||||
this._listDatabasesActionItem = this._instantiationService.createInstance(ListDatabasesActionItem, this, this._listDatabasesAction);
|
this._listDatabasesActionItem = this._instantiationService.createInstance(ListDatabasesActionItem, this, this._listDatabasesAction);
|
||||||
this._register(attachEditableDropdownStyler(this._listDatabasesActionItem, this.themeService));
|
this._register(this._listDatabasesActionItem.attachStyler(this.themeService));
|
||||||
}
|
}
|
||||||
return this._listDatabasesActionItem;
|
return this._listDatabasesActionItem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ export class QueryResultsEditor extends BaseEditor {
|
|||||||
protected _input: QueryResultsInput;
|
protected _input: QueryResultsInput;
|
||||||
|
|
||||||
private resultsView: QueryResultsView;
|
private resultsView: QueryResultsView;
|
||||||
|
private styleSheet = DOM.createStyleSheet();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ITelemetryService telemetryService: ITelemetryService,
|
@ITelemetryService telemetryService: ITelemetryService,
|
||||||
@@ -103,12 +104,13 @@ export class QueryResultsEditor extends BaseEditor {
|
|||||||
) {
|
) {
|
||||||
super(QueryResultsEditor.ID, telemetryService, themeService);
|
super(QueryResultsEditor.ID, telemetryService, themeService);
|
||||||
this._rawOptions = BareResultsGridInfo.createFromRawSettings(this._configurationService.getValue('resultsGrid'), getZoomLevel());
|
this._rawOptions = BareResultsGridInfo.createFromRawSettings(this._configurationService.getValue('resultsGrid'), getZoomLevel());
|
||||||
// this._configurationService.onDidChangeConfiguration(e => {
|
this._configurationService.onDidChangeConfiguration(e => {
|
||||||
// if (e.affectsConfiguration('resultsGrid')) {
|
if (e.affectsConfiguration('resultsGrid')) {
|
||||||
// this._rawOptions = BareResultsGridInfo.createFromRawSettings(this._configurationService.getValue('resultsGrid'), getZoomLevel());
|
this._rawOptions = BareResultsGridInfo.createFromRawSettings(this._configurationService.getValue('resultsGrid'), getZoomLevel());
|
||||||
// this.applySettings();
|
this.applySettings();
|
||||||
// }
|
}
|
||||||
// });
|
});
|
||||||
|
this.applySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
public get input(): QueryResultsInput {
|
public get input(): QueryResultsInput {
|
||||||
@@ -116,23 +118,20 @@ export class QueryResultsEditor extends BaseEditor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private applySettings() {
|
private applySettings() {
|
||||||
if (this.input && this.input.container) {
|
let cssRuleText = '';
|
||||||
if (!this.input.css) {
|
if (types.isNumber(this._rawOptions.cellPadding)) {
|
||||||
this.input.css = DOM.createStyleSheet(this.input.container);
|
cssRuleText = this._rawOptions.cellPadding + 'px';
|
||||||
}
|
} else {
|
||||||
let cssRuleText = '';
|
cssRuleText = this._rawOptions.cellPadding.join('px ') + 'px;';
|
||||||
if (types.isNumber(this._rawOptions.cellPadding)) {
|
|
||||||
cssRuleText = this._rawOptions.cellPadding + 'px';
|
|
||||||
} else {
|
|
||||||
cssRuleText = this._rawOptions.cellPadding.join('px ') + 'px;';
|
|
||||||
}
|
|
||||||
let content = `.grid .slick-cell { padding: ${cssRuleText}; }`;
|
|
||||||
content += `.grid { ${getBareResultsGridInfoStyles(this._rawOptions)} }`;
|
|
||||||
this.input.css.innerHTML = content;
|
|
||||||
}
|
}
|
||||||
|
let content = `.grid-panel .monaco-table .slick-cell { padding: ${cssRuleText} }`;
|
||||||
|
content += `.grid-panel .monaco-table { ${getBareResultsGridInfoStyles(this._rawOptions)} }`;
|
||||||
|
this.styleSheet.innerHTML = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
createEditor(parent: HTMLElement): void {
|
createEditor(parent: HTMLElement): void {
|
||||||
|
this.styleSheet.remove();
|
||||||
|
parent.appendChild(this.styleSheet);
|
||||||
if (!this.resultsView) {
|
if (!this.resultsView) {
|
||||||
this.resultsView = new QueryResultsView(parent, this._instantiationService, this._queryModelService);
|
this.resultsView = new QueryResultsView(parent, this._instantiationService, this._queryModelService);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import { QueryResultsInput } from 'sql/parts/query/common/queryResultsInput';
|
import { QueryResultsInput, ResultsViewState } from 'sql/parts/query/common/queryResultsInput';
|
||||||
import { TabbedPanel, IPanelTab, IPanelView } from 'sql/base/browser/ui/panel/panel';
|
import { TabbedPanel, IPanelTab, IPanelView } from 'sql/base/browser/ui/panel/panel';
|
||||||
import { IQueryModelService } from '../execution/queryModel';
|
import { IQueryModelService } from '../execution/queryModel';
|
||||||
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
import QueryRunner from 'sql/parts/query/execution/queryRunner';
|
||||||
@@ -14,11 +14,11 @@ import { ChartTab } from './charting/chartTab';
|
|||||||
import { QueryPlanTab } from 'sql/parts/queryPlan/queryPlan';
|
import { QueryPlanTab } from 'sql/parts/queryPlan/queryPlan';
|
||||||
|
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import * as UUID from 'vs/base/common/uuid';
|
|
||||||
import { PanelViewlet } from 'vs/workbench/browser/parts/views/panelViewlet';
|
import { PanelViewlet } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import * as DOM from 'vs/base/browser/dom';
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
import { once } from 'vs/base/common/event';
|
import { once, anyEvent } from 'vs/base/common/event';
|
||||||
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
class ResultsView implements IPanelView {
|
class ResultsView implements IPanelView {
|
||||||
private panelViewlet: PanelViewlet;
|
private panelViewlet: PanelViewlet;
|
||||||
@@ -26,25 +26,72 @@ class ResultsView implements IPanelView {
|
|||||||
private messagePanel: MessagePanel;
|
private messagePanel: MessagePanel;
|
||||||
private container = document.createElement('div');
|
private container = document.createElement('div');
|
||||||
private currentDimension: DOM.Dimension;
|
private currentDimension: DOM.Dimension;
|
||||||
|
private needsGridResize = false;
|
||||||
|
private _state: ResultsViewState;
|
||||||
|
|
||||||
constructor(instantiationService: IInstantiationService) {
|
constructor(private instantiationService: IInstantiationService) {
|
||||||
this.panelViewlet = instantiationService.createInstance(PanelViewlet, 'resultsView', { showHeaderInTitleWhenSingleView: false });
|
|
||||||
this.gridPanel = instantiationService.createInstance(GridPanel, { title: nls.localize('gridPanel', 'Results') });
|
this.panelViewlet = this.instantiationService.createInstance(PanelViewlet, 'resultsView', { showHeaderInTitleWhenSingleView: false });
|
||||||
this.messagePanel = instantiationService.createInstance(MessagePanel, { title: nls.localize('messagePanel', 'Messages') });
|
this.gridPanel = this.instantiationService.createInstance(GridPanel, { title: nls.localize('gridPanel', 'Results'), id: 'gridPanel' });
|
||||||
|
this.messagePanel = this.instantiationService.createInstance(MessagePanel, { title: nls.localize('messagePanel', 'Messages'), minimumBodySize: 0, id: 'messagePanel' });
|
||||||
this.gridPanel.render();
|
this.gridPanel.render();
|
||||||
this.messagePanel.render();
|
this.messagePanel.render();
|
||||||
this.panelViewlet.create(this.container).then(() => {
|
this.panelViewlet.create(this.container).then(() => {
|
||||||
|
this.gridPanel.setVisible(false);
|
||||||
this.panelViewlet.addPanels([
|
this.panelViewlet.addPanels([
|
||||||
{ panel: this.gridPanel, size: 1000, index: 0 },
|
|
||||||
{ panel: this.messagePanel, size: this.messagePanel.minimumSize, index: 1 }
|
{ panel: this.messagePanel, size: this.messagePanel.minimumSize, index: 1 }
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
let gridResizeList = this.gridPanel.onDidChange(e => {
|
anyEvent(this.gridPanel.onDidChange, this.messagePanel.onDidChange)(e => {
|
||||||
this.panelViewlet.resizePanel(this.gridPanel, this.gridPanel.maximumSize);
|
let size = this.gridPanel.maximumBodySize;
|
||||||
|
if (size < 1 && this.gridPanel.isVisible()) {
|
||||||
|
this.gridPanel.setVisible(false);
|
||||||
|
this.panelViewlet.removePanels([this.gridPanel]);
|
||||||
|
this.gridPanel.layout(0);
|
||||||
|
} else if (size > 0 && !this.gridPanel.isVisible()) {
|
||||||
|
this.gridPanel.setVisible(true);
|
||||||
|
let panelSize: number;
|
||||||
|
if (this.state && this.state.gridPanelSize) {
|
||||||
|
panelSize = this.state.gridPanelSize;
|
||||||
|
} else if (this.currentDimension) {
|
||||||
|
panelSize = Math.round(this.currentDimension.height * .7);
|
||||||
|
} else {
|
||||||
|
panelSize = 200;
|
||||||
|
this.needsGridResize = true;
|
||||||
|
}
|
||||||
|
this.panelViewlet.addPanels([{ panel: this.gridPanel, index: 0, size: panelSize }]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
let resizeList = anyEvent(this.gridPanel.onDidChange, this.messagePanel.onDidChange)(() => {
|
||||||
|
let panelSize: number;
|
||||||
|
if (this.state && this.state.gridPanelSize) {
|
||||||
|
panelSize = this.state.gridPanelSize;
|
||||||
|
} else if (this.currentDimension) {
|
||||||
|
panelSize = Math.round(this.currentDimension.height * .7);
|
||||||
|
} else {
|
||||||
|
panelSize = 200;
|
||||||
|
this.needsGridResize = true;
|
||||||
|
}
|
||||||
|
if (this.state.messagePanelSize) {
|
||||||
|
this.panelViewlet.resizePanel(this.gridPanel, this.state.messagePanelSize);
|
||||||
|
}
|
||||||
|
this.panelViewlet.resizePanel(this.gridPanel, panelSize);
|
||||||
|
})
|
||||||
// once the user changes the sash we should stop trying to resize the grid
|
// once the user changes the sash we should stop trying to resize the grid
|
||||||
once(this.panelViewlet.onDidSashChange)(e => {
|
once(this.panelViewlet.onDidSashChange)(e => {
|
||||||
gridResizeList.dispose();
|
this.needsGridResize = false;
|
||||||
|
resizeList.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.panelViewlet.onDidSashChange(e => {
|
||||||
|
if (this.state) {
|
||||||
|
if (this.gridPanel.isExpanded()) {
|
||||||
|
this.state.gridPanelSize = this.panelViewlet.getPanelSize(this.gridPanel);
|
||||||
|
}
|
||||||
|
if (this.messagePanel.isExpanded()) {
|
||||||
|
this.state.messagePanelSize = this.panelViewlet.getPanelSize(this.messagePanel);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +106,9 @@ class ResultsView implements IPanelView {
|
|||||||
this.gridPanel.layout(dimension.height);
|
this.gridPanel.layout(dimension.height);
|
||||||
}
|
}
|
||||||
this.currentDimension = dimension;
|
this.currentDimension = dimension;
|
||||||
|
if (this.needsGridResize) {
|
||||||
|
this.panelViewlet.resizePanel(this.gridPanel, this.state.gridPanelSize || Math.round(this.currentDimension.height * .7));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(): void {
|
remove(): void {
|
||||||
@@ -73,11 +123,21 @@ class ResultsView implements IPanelView {
|
|||||||
public hideResultHeader() {
|
public hideResultHeader() {
|
||||||
this.gridPanel.headerVisible = false;
|
this.gridPanel.headerVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public set state(val: ResultsViewState) {
|
||||||
|
this._state = val;
|
||||||
|
this.gridPanel.state = val.gridPanelState;
|
||||||
|
this.messagePanel.state = val.messagePanelState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get state(): ResultsViewState {
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResultsTab implements IPanelTab {
|
class ResultsTab implements IPanelTab {
|
||||||
public readonly title = nls.localize('resultsTabTitle', 'Results');
|
public readonly title = nls.localize('resultsTabTitle', 'Results');
|
||||||
public readonly identifier = UUID.generateUuid();
|
public readonly identifier = 'resultsTab';
|
||||||
public readonly view: ResultsView;
|
public readonly view: ResultsView;
|
||||||
|
|
||||||
constructor(instantiationService: IInstantiationService) {
|
constructor(instantiationService: IInstantiationService) {
|
||||||
@@ -96,6 +156,8 @@ export class QueryResultsView {
|
|||||||
private chartTab: ChartTab;
|
private chartTab: ChartTab;
|
||||||
private qpTab: QueryPlanTab;
|
private qpTab: QueryPlanTab;
|
||||||
|
|
||||||
|
private runnerDisposables: IDisposable[];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
@IInstantiationService instantiationService: IInstantiationService,
|
@IInstantiationService instantiationService: IInstantiationService,
|
||||||
@@ -105,6 +167,12 @@ export class QueryResultsView {
|
|||||||
this.chartTab = new ChartTab(instantiationService);
|
this.chartTab = new ChartTab(instantiationService);
|
||||||
this._panelView = new TabbedPanel(container, { showHeaderWhenSingleView: false });
|
this._panelView = new TabbedPanel(container, { showHeaderWhenSingleView: false });
|
||||||
this.qpTab = new QueryPlanTab();
|
this.qpTab = new QueryPlanTab();
|
||||||
|
this._panelView.pushTab(this.resultsTab);
|
||||||
|
this._panelView.onTabChange(e => {
|
||||||
|
if (this.input) {
|
||||||
|
this.input.state.activeTab = e;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public style() {
|
public style() {
|
||||||
@@ -112,11 +180,32 @@ export class QueryResultsView {
|
|||||||
|
|
||||||
public set input(input: QueryResultsInput) {
|
public set input(input: QueryResultsInput) {
|
||||||
this._input = input;
|
this._input = input;
|
||||||
|
dispose(this.runnerDisposables);
|
||||||
|
this.runnerDisposables = [];
|
||||||
|
this.resultsTab.view.state = this.input.state;
|
||||||
|
this.qpTab.view.state = this.input.state.queryPlanState;
|
||||||
|
this.chartTab.view.state = this.input.state.chartState;
|
||||||
let queryRunner = this.queryModelService._getQueryInfo(input.uri).queryRunner;
|
let queryRunner = this.queryModelService._getQueryInfo(input.uri).queryRunner;
|
||||||
this.resultsTab.queryRunner = queryRunner;
|
this.resultsTab.queryRunner = queryRunner;
|
||||||
this.chartTab.queryRunner = queryRunner;
|
this.chartTab.queryRunner = queryRunner;
|
||||||
if (!this._panelView.contains(this.resultsTab)) {
|
this.runnerDisposables.push(queryRunner.onQueryStart(e => {
|
||||||
this._panelView.pushTab(this.resultsTab);
|
this.hideChart();
|
||||||
|
this.hidePlan();
|
||||||
|
this.input.state.visibleTabs = new Set();
|
||||||
|
this.input.state.activeTab = this.resultsTab.identifier;
|
||||||
|
}));
|
||||||
|
if (this.input.state.visibleTabs.has(this.chartTab.identifier)) {
|
||||||
|
if (!this._panelView.contains(this.chartTab)) {
|
||||||
|
this._panelView.pushTab(this.chartTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.input.state.visibleTabs.has(this.qpTab.identifier)) {
|
||||||
|
if (!this._panelView.contains(this.qpTab)) {
|
||||||
|
this._panelView.pushTab(this.qpTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.input.state.activeTab) {
|
||||||
|
this._panelView.showTab(this.input.state.activeTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +222,7 @@ export class QueryResultsView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public chartData(dataId: { resultId: number, batchId: number }): void {
|
public chartData(dataId: { resultId: number, batchId: number }): void {
|
||||||
|
this.input.state.visibleTabs.add(this.chartTab.identifier);
|
||||||
if (!this._panelView.contains(this.chartTab)) {
|
if (!this._panelView.contains(this.chartTab)) {
|
||||||
this._panelView.pushTab(this.chartTab);
|
this._panelView.pushTab(this.chartTab);
|
||||||
}
|
}
|
||||||
@@ -141,7 +231,14 @@ export class QueryResultsView {
|
|||||||
this.chartTab.chart(dataId);
|
this.chartTab.chart(dataId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hideChart() {
|
||||||
|
if (this._panelView.contains(this.chartTab)) {
|
||||||
|
this._panelView.removeTab(this.chartTab.identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public showPlan(xml: string) {
|
public showPlan(xml: string) {
|
||||||
|
this.input.state.visibleTabs.add(this.qpTab.identifier);
|
||||||
if (!this._panelView.contains(this.qpTab)) {
|
if (!this._panelView.contains(this.qpTab)) {
|
||||||
this._panelView.pushTab(this.qpTab);
|
this._panelView.pushTab(this.qpTab);
|
||||||
}
|
}
|
||||||
@@ -149,4 +246,10 @@ export class QueryResultsView {
|
|||||||
this._panelView.showTab(this.qpTab.identifier);
|
this._panelView.showTab(this.qpTab.identifier);
|
||||||
this.qpTab.view.showPlan(xml);
|
this.qpTab.view.showPlan(xml);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hidePlan() {
|
||||||
|
if (this._panelView.contains(this.qpTab)) {
|
||||||
|
this._panelView.removeTab(this.qpTab.identifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import 'vs/css!sql/parts/query/editor/media/queryActions';
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import { Builder, $ } from 'vs/base/browser/builder';
|
import { Builder, $ } from 'vs/base/browser/builder';
|
||||||
import { Dropdown } from 'sql/base/browser/ui/editableDropdown/dropdown';
|
import { Dropdown } from 'sql/base/browser/ui/editableDropdown/dropdown';
|
||||||
@@ -12,6 +13,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
|||||||
import { TPromise } from 'vs/base/common/winjs.base';
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
|
import { attachEditableDropdownStyler, attachSelectBoxStyler } from 'sql/common/theme/styler';
|
||||||
|
|
||||||
import { ISelectionData } from 'sqlops';
|
import { ISelectionData } from 'sqlops';
|
||||||
import {
|
import {
|
||||||
@@ -25,6 +27,8 @@ import { QueryEditor } from 'sql/parts/query/editor/queryEditor';
|
|||||||
import { IQueryModelService } from 'sql/parts/query/execution/queryModel';
|
import { IQueryModelService } from 'sql/parts/query/execution/queryModel';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
|
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
|
||||||
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action class that query-based Actions will extend. This base class automatically handles activating and
|
* Action class that query-based Actions will extend. This base class automatically handles activating and
|
||||||
@@ -267,7 +271,11 @@ export class ActualQueryPlanAction extends QueryTaskbarAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.isConnected(editor)) {
|
if (this.isConnected(editor)) {
|
||||||
editor.currentQueryInput.runQuery(editor.getSelection(), {
|
let selection = editor.getSelection();
|
||||||
|
if (!selection) {
|
||||||
|
selection = editor.getAllSelection();
|
||||||
|
}
|
||||||
|
editor.currentQueryInput.runQuery(selection, {
|
||||||
displayActualQueryPlan: true
|
displayActualQueryPlan: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -431,6 +439,9 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
|
|||||||
private _isConnected: boolean;
|
private _isConnected: boolean;
|
||||||
private $databaseListDropdown: Builder;
|
private $databaseListDropdown: Builder;
|
||||||
private _dropdown: Dropdown;
|
private _dropdown: Dropdown;
|
||||||
|
private _databaseSelectBox: SelectBox;
|
||||||
|
private _isInAccessibilityMode: boolean;
|
||||||
|
private readonly _selectDatabaseString: string = nls.localize("selectDatabase", "Select Database");
|
||||||
|
|
||||||
// CONSTRUCTOR /////////////////////////////////////////////////////////
|
// CONSTRUCTOR /////////////////////////////////////////////////////////
|
||||||
constructor(
|
constructor(
|
||||||
@@ -439,23 +450,33 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
|
|||||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||||
@INotificationService private _notificationService: INotificationService,
|
@INotificationService private _notificationService: INotificationService,
|
||||||
@IContextViewService contextViewProvider: IContextViewService,
|
@IContextViewService contextViewProvider: IContextViewService,
|
||||||
@IThemeService themeService: IThemeService
|
@IThemeService themeService: IThemeService,
|
||||||
|
@IConfigurationService private readonly _configurationService: IConfigurationService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._toDispose = [];
|
this._toDispose = [];
|
||||||
this.$databaseListDropdown = $('.databaseListDropdown');
|
this.$databaseListDropdown = $('.databaseListDropdown');
|
||||||
let selectString = nls.localize("selectDatabase", "Select Database");
|
this._isInAccessibilityMode = this._configurationService.getValue('editor.accessibilitySupport') === 'on';
|
||||||
this._dropdown = new Dropdown(this.$databaseListDropdown.getHTMLElement(), contextViewProvider, themeService, {
|
|
||||||
strictSelection: true,
|
if (this._isInAccessibilityMode) {
|
||||||
placeholder: selectString,
|
this._databaseSelectBox = new SelectBox([this._selectDatabaseString], this._selectDatabaseString, contextViewProvider, undefined, { ariaLabel: this._selectDatabaseString });
|
||||||
ariaLabel: selectString,
|
this._databaseSelectBox.render(this.$databaseListDropdown.getHTMLElement());
|
||||||
actionLabel: nls.localize('listDatabases.toggleDatabaseNameDropdown', 'Select Database Toggle Dropdown')
|
this._databaseSelectBox.onDidSelect(e => { this.databaseSelected(e.selected); });
|
||||||
});
|
this._databaseSelectBox.disable();
|
||||||
this._dropdown.onValueChange(s => this.databaseSelected(s));
|
|
||||||
|
} else {
|
||||||
|
this._dropdown = new Dropdown(this.$databaseListDropdown.getHTMLElement(), contextViewProvider, themeService, {
|
||||||
|
strictSelection: true,
|
||||||
|
placeholder: this._selectDatabaseString,
|
||||||
|
ariaLabel: this._selectDatabaseString,
|
||||||
|
actionLabel: nls.localize('listDatabases.toggleDatabaseNameDropdown', 'Select Database Toggle Dropdown')
|
||||||
|
});
|
||||||
|
this._dropdown.onValueChange(s => this.databaseSelected(s));
|
||||||
|
this._toDispose.push(this._dropdown.onFocus(() => { self.onDropdownFocus(); }));
|
||||||
|
}
|
||||||
|
|
||||||
// Register event handlers
|
// Register event handlers
|
||||||
let self = this;
|
let self = this;
|
||||||
this._toDispose.push(this._dropdown.onFocus(() => { self.onDropdownFocus(); }));
|
|
||||||
this._toDispose.push(this._connectionManagementService.onConnectionChanged(params => { self.onConnectionChanged(params); }));
|
this._toDispose.push(this._connectionManagementService.onConnectionChanged(params => { self.onConnectionChanged(params); }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +486,12 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
public style(styles) {
|
public style(styles) {
|
||||||
this._dropdown.style(styles);
|
if (this._isInAccessibilityMode) {
|
||||||
|
this._databaseSelectBox.style(styles);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._dropdown.style(styles);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public setActionContext(context: any): void {
|
public setActionContext(context: any): void {
|
||||||
@@ -477,11 +503,27 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
public focus(): void {
|
public focus(): void {
|
||||||
this._dropdown.focus();
|
if (this._isInAccessibilityMode) {
|
||||||
|
this._databaseSelectBox.focus();
|
||||||
|
} else {
|
||||||
|
this._dropdown.focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public blur(): void {
|
public blur(): void {
|
||||||
this._dropdown.blur();
|
if (this._isInAccessibilityMode) {
|
||||||
|
this._databaseSelectBox.blur();
|
||||||
|
} else {
|
||||||
|
this._dropdown.blur();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public attachStyler(themeService: IThemeService): IDisposable {
|
||||||
|
if (this._isInAccessibilityMode) {
|
||||||
|
return attachSelectBoxStyler(this, themeService);
|
||||||
|
} else {
|
||||||
|
return attachEditableDropdownStyler(this, themeService);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
@@ -496,9 +538,15 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
|
|||||||
|
|
||||||
public onDisconnect(): void {
|
public onDisconnect(): void {
|
||||||
this._isConnected = false;
|
this._isConnected = false;
|
||||||
this._dropdown.enabled = false;
|
|
||||||
this._currentDatabaseName = undefined;
|
this._currentDatabaseName = undefined;
|
||||||
this._dropdown.value = '';
|
|
||||||
|
if (this._isInAccessibilityMode) {
|
||||||
|
this._databaseSelectBox.disable();
|
||||||
|
this._databaseSelectBox.setOptions([this._selectDatabaseString]);
|
||||||
|
} else {
|
||||||
|
this._dropdown.enabled = false;
|
||||||
|
this._dropdown.value = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PRIVATE HELPERS /////////////////////////////////////////////////////
|
// PRIVATE HELPERS /////////////////////////////////////////////////////
|
||||||
@@ -515,22 +563,22 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
|
|||||||
|
|
||||||
this._connectionManagementService.changeDatabase(this._editor.uri, dbName)
|
this._connectionManagementService.changeDatabase(this._editor.uri, dbName)
|
||||||
.then(
|
.then(
|
||||||
result => {
|
result => {
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
this.resetDatabaseName();
|
||||||
|
this._notificationService.notify({
|
||||||
|
severity: Severity.Error,
|
||||||
|
message: nls.localize('changeDatabase.failed', "Failed to change database")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
this.resetDatabaseName();
|
this.resetDatabaseName();
|
||||||
this._notificationService.notify({
|
this._notificationService.notify({
|
||||||
severity: Severity.Error,
|
severity: Severity.Error,
|
||||||
message: nls.localize('changeDatabase.failed', "Failed to change database")
|
message: nls.localize('changeDatabase.failedWithError', "Failed to change database {0}", error)
|
||||||
});
|
});
|
||||||
}
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
this.resetDatabaseName();
|
|
||||||
this._notificationService.notify({
|
|
||||||
severity: Severity.Error,
|
|
||||||
message: nls.localize('changeDatabase.failedWithError', "Failed to change database {0}", error)
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCurrentDatabaseName() {
|
private getCurrentDatabaseName() {
|
||||||
@@ -545,7 +593,11 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
private resetDatabaseName() {
|
private resetDatabaseName() {
|
||||||
this._dropdown.value = this.getCurrentDatabaseName();
|
if (this._isInAccessibilityMode) {
|
||||||
|
this._databaseSelectBox.selectWithOptionName(this.getCurrentDatabaseName());
|
||||||
|
} else {
|
||||||
|
this._dropdown.value = this.getCurrentDatabaseName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onConnectionChanged(connParams: IConnectionParams): void {
|
private onConnectionChanged(connParams: IConnectionParams): void {
|
||||||
@@ -579,9 +631,26 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
|
|||||||
|
|
||||||
private updateConnection(databaseName: string) {
|
private updateConnection(databaseName: string) {
|
||||||
this._isConnected = true;
|
this._isConnected = true;
|
||||||
this._dropdown.enabled = true;
|
|
||||||
this._currentDatabaseName = databaseName;
|
this._currentDatabaseName = databaseName;
|
||||||
this._dropdown.value = databaseName;
|
|
||||||
|
if (this._isInAccessibilityMode) {
|
||||||
|
this._databaseSelectBox.enable();
|
||||||
|
let self = this;
|
||||||
|
let uri = self._editor.connectedUri;
|
||||||
|
if (!uri) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self._connectionManagementService.listDatabases(uri)
|
||||||
|
.then(result => {
|
||||||
|
if (result && result.databaseNames) {
|
||||||
|
this._databaseSelectBox.setOptions(result.databaseNames);
|
||||||
|
}
|
||||||
|
this._databaseSelectBox.selectWithOptionName(databaseName);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this._dropdown.enabled = true;
|
||||||
|
this._dropdown.value = databaseName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TESTING PROPERTIES //////////////////////////////////////////////////
|
// TESTING PROPERTIES //////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import * as WorkbenchUtils from 'sql/workbench/common/sqlWorkbenchUtils';
|
|||||||
import { IQueryManagementService } from 'sql/parts/query/common/queryManagement';
|
import { IQueryManagementService } from 'sql/parts/query/common/queryManagement';
|
||||||
import * as Utils from 'sql/parts/connection/common/utils';
|
import * as Utils from 'sql/parts/connection/common/utils';
|
||||||
import { SaveFormat } from 'sql/parts/grid/common/interfaces';
|
import { SaveFormat } from 'sql/parts/grid/common/interfaces';
|
||||||
import { echo } from 'sql/base/common/event';
|
import { echo, debounceEvent } from 'sql/base/common/event';
|
||||||
|
|
||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
||||||
@@ -22,9 +22,10 @@ import * as types from 'vs/base/common/types';
|
|||||||
import { EventEmitter } from 'sql/base/common/eventEmitter';
|
import { EventEmitter } from 'sql/base/common/eventEmitter';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
import { Emitter, debounceEvent, Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { ResultSerializer } from 'sql/parts/query/common/resultSerializer';
|
import { ResultSerializer } from 'sql/parts/query/common/resultSerializer';
|
||||||
|
import { TPromise } from 'vs/base/common/winjs.base';
|
||||||
|
|
||||||
export interface IEditSessionReadyEvent {
|
export interface IEditSessionReadyEvent {
|
||||||
ownerUri: string;
|
ownerUri: string;
|
||||||
@@ -73,25 +74,27 @@ export default class QueryRunner {
|
|||||||
public get isQueryPlan(): boolean { return this._isQueryPlan; }
|
public get isQueryPlan(): boolean { return this._isQueryPlan; }
|
||||||
|
|
||||||
private _onMessage = new Emitter<sqlops.IResultMessage>();
|
private _onMessage = new Emitter<sqlops.IResultMessage>();
|
||||||
private _echoedMessages = echo(debounceEvent<sqlops.IResultMessage, sqlops.IResultMessage[]>(this._onMessage.event, (l, e) => {
|
private _debouncedMessage = debounceEvent<sqlops.IResultMessage, sqlops.IResultMessage[]>(this._onMessage.event, (l, e) => {
|
||||||
// on first run
|
// on first run
|
||||||
if (types.isUndefinedOrNull(l)) {
|
if (types.isUndefinedOrNull(l)) {
|
||||||
return [e];
|
return [e];
|
||||||
} else {
|
} else {
|
||||||
return l.concat(e);
|
return l.concat(e);
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
|
private _echoedMessages = echo(this._debouncedMessage.event);
|
||||||
public readonly onMessage = this._echoedMessages.event;
|
public readonly onMessage = this._echoedMessages.event;
|
||||||
|
|
||||||
private _onResultSet = new Emitter<sqlops.ResultSetSummary>();
|
private _onResultSet = new Emitter<sqlops.ResultSetSummary>();
|
||||||
private _echoedResultSet = echo(debounceEvent<sqlops.ResultSetSummary, sqlops.ResultSetSummary[]>(this._onResultSet.event, (l, e) => {
|
private _debouncedResultSet = debounceEvent<sqlops.ResultSetSummary, sqlops.ResultSetSummary[]>(this._onResultSet.event, (l, e) => {
|
||||||
// on first run
|
// on first run
|
||||||
if (types.isUndefinedOrNull(l)) {
|
if (types.isUndefinedOrNull(l)) {
|
||||||
return [e];
|
return [e];
|
||||||
} else {
|
} else {
|
||||||
return l.concat(e);
|
return l.concat(e);
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
|
private _echoedResultSet = echo(this._debouncedResultSet.event);
|
||||||
public readonly onResultSet = this._echoedResultSet.event;
|
public readonly onResultSet = this._echoedResultSet.event;
|
||||||
|
|
||||||
private _onQueryStart = new Emitter<void>();
|
private _onQueryStart = new Emitter<void>();
|
||||||
@@ -171,8 +174,13 @@ export default class QueryRunner {
|
|||||||
private doRunQuery(input: string, runCurrentStatement: boolean, runOptions?: sqlops.ExecutionPlanOptions): Thenable<void>;
|
private doRunQuery(input: string, runCurrentStatement: boolean, runOptions?: sqlops.ExecutionPlanOptions): Thenable<void>;
|
||||||
private doRunQuery(input: sqlops.ISelectionData, runCurrentStatement: boolean, runOptions?: sqlops.ExecutionPlanOptions): Thenable<void>;
|
private doRunQuery(input: sqlops.ISelectionData, runCurrentStatement: boolean, runOptions?: sqlops.ExecutionPlanOptions): Thenable<void>;
|
||||||
private doRunQuery(input, runCurrentStatement: boolean, runOptions?: sqlops.ExecutionPlanOptions): Thenable<void> {
|
private doRunQuery(input, runCurrentStatement: boolean, runOptions?: sqlops.ExecutionPlanOptions): Thenable<void> {
|
||||||
|
if (this.isExecuting) {
|
||||||
|
return TPromise.as(undefined);
|
||||||
|
}
|
||||||
this._echoedMessages.clear();
|
this._echoedMessages.clear();
|
||||||
this._echoedResultSet.clear();
|
this._echoedResultSet.clear();
|
||||||
|
this._debouncedMessage.clear();
|
||||||
|
this._debouncedResultSet.clear();
|
||||||
let ownerUri = this.uri;
|
let ownerUri = this.uri;
|
||||||
this._batchSets = [];
|
this._batchSets = [];
|
||||||
this._hasCompleted = false;
|
this._hasCompleted = false;
|
||||||
|
|||||||
@@ -13,9 +13,13 @@ import { localize } from 'vs/nls';
|
|||||||
import * as UUID from 'vs/base/common/uuid';
|
import * as UUID from 'vs/base/common/uuid';
|
||||||
import { Builder } from 'vs/base/browser/builder';
|
import { Builder } from 'vs/base/browser/builder';
|
||||||
|
|
||||||
|
export class QueryPlanState {
|
||||||
|
xml: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class QueryPlanTab implements IPanelTab {
|
export class QueryPlanTab implements IPanelTab {
|
||||||
public readonly title = localize('queryPlanTitle', 'Query Plan');
|
public readonly title = localize('queryPlanTitle', 'Query Plan');
|
||||||
public readonly identifier = UUID.generateUuid();
|
public readonly identifier = 'QueryPlanTab';
|
||||||
public readonly view: QueryPlanView;
|
public readonly view: QueryPlanView;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -27,6 +31,7 @@ export class QueryPlanView implements IPanelView {
|
|||||||
private qp: QueryPlan;
|
private qp: QueryPlan;
|
||||||
private xml: string;
|
private xml: string;
|
||||||
private container = document.createElement('div');
|
private container = document.createElement('div');
|
||||||
|
private _state: QueryPlanState;
|
||||||
|
|
||||||
public render(container: HTMLElement): void {
|
public render(container: HTMLElement): void {
|
||||||
if (!this.qp) {
|
if (!this.qp) {
|
||||||
@@ -36,6 +41,7 @@ export class QueryPlanView implements IPanelView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
container.appendChild(this.container);
|
container.appendChild(this.container);
|
||||||
|
container.style.overflow = 'scroll';
|
||||||
}
|
}
|
||||||
|
|
||||||
public layout(dimension: Dimension): void {
|
public layout(dimension: Dimension): void {
|
||||||
@@ -47,6 +53,20 @@ export class QueryPlanView implements IPanelView {
|
|||||||
} else {
|
} else {
|
||||||
this.xml = xml;
|
this.xml = xml;
|
||||||
}
|
}
|
||||||
|
if (this.state) {
|
||||||
|
this.state.xml = xml;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public set state(val: QueryPlanState) {
|
||||||
|
this._state = val;
|
||||||
|
if (this.state.xml) {
|
||||||
|
this.showPlan(this.state.xml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get state(): QueryPlanState {
|
||||||
|
return this._state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ const viewletDescriptor = new ViewletDescriptor(
|
|||||||
VIEWLET_ID,
|
VIEWLET_ID,
|
||||||
'Task History',
|
'Task History',
|
||||||
'taskHistoryViewlet',
|
'taskHistoryViewlet',
|
||||||
-90
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);
|
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);
|
||||||
|
|||||||
@@ -48,9 +48,7 @@ export abstract class Task {
|
|||||||
id: this.id,
|
id: this.id,
|
||||||
handler: (accessor, profile, args) => this.runTask(accessor, profile, args),
|
handler: (accessor, profile, args) => this.runTask(accessor, profile, args),
|
||||||
description: this._description,
|
description: this._description,
|
||||||
iconClass: this._iconClass,
|
iconClass: this._iconClass
|
||||||
iconPath: this.opts.iconPath,
|
|
||||||
title: this.title
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,10 +60,8 @@ export abstract class Task {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public registerTask(showInCommandPalette: boolean = true): IDisposable {
|
public registerTask(): IDisposable {
|
||||||
if (showInCommandPalette) {
|
MenuRegistry.addCommand(this.toCommandAction());
|
||||||
MenuRegistry.addCommand(this.toCommandAction());
|
|
||||||
}
|
|
||||||
return TaskRegistry.registerTask(this.toITask());
|
return TaskRegistry.registerTask(this.toITask());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,8 +96,6 @@ export interface ITask {
|
|||||||
precondition?: ContextKeyExpr;
|
precondition?: ContextKeyExpr;
|
||||||
description?: ITaskHandlerDescription;
|
description?: ITaskHandlerDescription;
|
||||||
iconClass?: string;
|
iconClass?: string;
|
||||||
iconPath?: { dark: string; light?: string; };
|
|
||||||
title?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITaskRegistry {
|
export interface ITaskRegistry {
|
||||||
@@ -110,7 +104,6 @@ export interface ITaskRegistry {
|
|||||||
getTasks(): string[];
|
getTasks(): string[];
|
||||||
getOrCreateTaskIconClassName(item: ICommandAction): string;
|
getOrCreateTaskIconClassName(item: ICommandAction): string;
|
||||||
onTaskRegistered: Event<string>;
|
onTaskRegistered: Event<string>;
|
||||||
getCommandActionById(id: string): ICommandAction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ids = new IdGenerator('task-icon-');
|
const ids = new IdGenerator('task-icon-');
|
||||||
@@ -121,7 +114,6 @@ export const TaskRegistry: ITaskRegistry = new class implements ITaskRegistry {
|
|||||||
private _onTaskRegistered = new Emitter<string>();
|
private _onTaskRegistered = new Emitter<string>();
|
||||||
public readonly onTaskRegistered: Event<string> = this._onTaskRegistered.event;
|
public readonly onTaskRegistered: Event<string> = this._onTaskRegistered.event;
|
||||||
private taskIdToIconClassNameMap: Map<string /* task id */, string /* CSS rule */> = new Map<string, string>();
|
private taskIdToIconClassNameMap: Map<string /* task id */, string /* CSS rule */> = new Map<string, string>();
|
||||||
private taskIdToCommandActionMap: Map<string, ICommandAction> = new Map<string, ICommandAction>();
|
|
||||||
|
|
||||||
registerTask(idOrTask: string | ITask, handler?: ITaskHandler): IDisposable {
|
registerTask(idOrTask: string | ITask, handler?: ITaskHandler): IDisposable {
|
||||||
let disposable: IDisposable;
|
let disposable: IDisposable;
|
||||||
@@ -133,16 +125,6 @@ export const TaskRegistry: ITaskRegistry = new class implements ITaskRegistry {
|
|||||||
if (idOrTask.iconClass) {
|
if (idOrTask.iconClass) {
|
||||||
this.taskIdToIconClassNameMap.set(idOrTask.id, idOrTask.iconClass);
|
this.taskIdToIconClassNameMap.set(idOrTask.id, idOrTask.iconClass);
|
||||||
}
|
}
|
||||||
if (idOrTask.iconPath && idOrTask.title) {
|
|
||||||
this.taskIdToCommandActionMap.set(idOrTask.id, {
|
|
||||||
iconLocation: {
|
|
||||||
dark: URI.parse(idOrTask.iconPath.dark),
|
|
||||||
light: URI.parse(idOrTask.iconPath.light),
|
|
||||||
},
|
|
||||||
id: idOrTask.id,
|
|
||||||
title: idOrTask.title
|
|
||||||
});
|
|
||||||
}
|
|
||||||
disposable = CommandsRegistry.registerCommand(idOrTask);
|
disposable = CommandsRegistry.registerCommand(idOrTask);
|
||||||
id = idOrTask.id;
|
id = idOrTask.id;
|
||||||
}
|
}
|
||||||
@@ -177,8 +159,4 @@ export const TaskRegistry: ITaskRegistry = new class implements ITaskRegistry {
|
|||||||
getTasks(): string[] {
|
getTasks(): string[] {
|
||||||
return this._tasks.slice(0);
|
return this._tasks.slice(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCommandActionById(taskId: string): ICommandAction {
|
|
||||||
return this.taskIdToCommandActionMap.get(taskId);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
5
src/sql/sqlops.d.ts
vendored
5
src/sql/sqlops.d.ts
vendored
@@ -185,6 +185,11 @@ declare module 'sqlops' {
|
|||||||
* Get the parent node. Returns undefined if there is none.
|
* Get the parent node. Returns undefined if there is none.
|
||||||
*/
|
*/
|
||||||
getParent(): Thenable<ObjectExplorerNode>;
|
getParent(): Thenable<ObjectExplorerNode>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the node, expanding it if it has children
|
||||||
|
*/
|
||||||
|
refresh(): Thenable<void>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
88
src/sql/sqlops.proposed.d.ts
vendored
88
src/sql/sqlops.proposed.d.ts
vendored
@@ -17,7 +17,9 @@ declare module 'sqlops' {
|
|||||||
*/
|
*/
|
||||||
export interface ModelBuilder {
|
export interface ModelBuilder {
|
||||||
navContainer(): ContainerBuilder<NavContainer, any, any>;
|
navContainer(): ContainerBuilder<NavContainer, any, any>;
|
||||||
|
divContainer(): DivBuilder;
|
||||||
flexContainer(): FlexBuilder;
|
flexContainer(): FlexBuilder;
|
||||||
|
dom(): ComponentBuilder<DomComponent>
|
||||||
card(): ComponentBuilder<CardComponent>;
|
card(): ComponentBuilder<CardComponent>;
|
||||||
inputBox(): ComponentBuilder<InputBoxComponent>;
|
inputBox(): ComponentBuilder<InputBoxComponent>;
|
||||||
checkBox(): ComponentBuilder<CheckBoxComponent>;
|
checkBox(): ComponentBuilder<CheckBoxComponent>;
|
||||||
@@ -72,6 +74,10 @@ declare module 'sqlops' {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DivBuilder extends ContainerBuilder<DivContainer, DivLayout, DivItemLayout> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export interface GroupBuilder extends ContainerBuilder<GroupContainer, GroupLayout, GroupItemLayout> {
|
export interface GroupBuilder extends ContainerBuilder<GroupContainer, GroupLayout, GroupItemLayout> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,6 +352,33 @@ declare module 'sqlops' {
|
|||||||
export interface GroupItemLayout {
|
export interface GroupItemLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DivLayout {
|
||||||
|
/**
|
||||||
|
* Container Height
|
||||||
|
*/
|
||||||
|
height?: number | string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container Width
|
||||||
|
*/
|
||||||
|
width?: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DivItemLayout {
|
||||||
|
/**
|
||||||
|
* Matches the order CSS property and its available values.
|
||||||
|
*/
|
||||||
|
order?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches the CSS style key and its available values.
|
||||||
|
*/
|
||||||
|
CSSStyles?: { [key: string]: string };
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DivContainer extends Container<DivLayout, DivItemLayout>, DivContainerProperties {
|
||||||
|
}
|
||||||
|
|
||||||
export interface FlexContainer extends Container<FlexLayout, FlexItemLayout> {
|
export interface FlexContainer extends Container<FlexLayout, FlexItemLayout> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,6 +576,13 @@ declare module 'sqlops' {
|
|||||||
options?: vscode.WebviewOptions;
|
options?: vscode.WebviewOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DomProperties extends ComponentProperties {
|
||||||
|
/**
|
||||||
|
* Contents of the DOM component.
|
||||||
|
*/
|
||||||
|
html?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Editor properties for the editor component
|
* Editor properties for the editor component
|
||||||
*/
|
*/
|
||||||
@@ -561,17 +601,35 @@ declare module 'sqlops' {
|
|||||||
label?: string;
|
label?: string;
|
||||||
isFile?: boolean;
|
isFile?: boolean;
|
||||||
fileContent?: string;
|
fileContent?: string;
|
||||||
|
title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingComponentProperties {
|
export interface LoadingComponentProperties {
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DivContainerProperties extends ComponentProperties {
|
||||||
|
/**
|
||||||
|
* Matches the overflow-y CSS property and its available values.
|
||||||
|
*/
|
||||||
|
overflowY?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setting the scroll based on the y offset
|
||||||
|
* This is used when its child component is webview
|
||||||
|
*/
|
||||||
|
yOffsetChange?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CardComponent extends Component, CardProperties {
|
export interface CardComponent extends Component, CardProperties {
|
||||||
onDidActionClick: vscode.Event<ActionDescriptor>;
|
onDidActionClick: vscode.Event<ActionDescriptor>;
|
||||||
onCardSelectedChanged: vscode.Event<any>;
|
onCardSelectedChanged: vscode.Event<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DomComponent extends Component, DomProperties {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export interface TextComponent extends Component {
|
export interface TextComponent extends Component {
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
@@ -662,8 +720,22 @@ declare module 'sqlops' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ButtonComponent extends Component, ButtonProperties {
|
export interface ButtonComponent extends Component, ButtonProperties {
|
||||||
|
/**
|
||||||
|
* The label for the button
|
||||||
|
*/
|
||||||
label: string;
|
label: string;
|
||||||
|
/**
|
||||||
|
* The title for the button. This title will show when it hovers
|
||||||
|
*/
|
||||||
|
title: string;
|
||||||
|
/**
|
||||||
|
* Icon Path for the button.
|
||||||
|
*/
|
||||||
iconPath: string | vscode.Uri | { light: string | vscode.Uri; dark: string | vscode.Uri };
|
iconPath: string | vscode.Uri | { light: string | vscode.Uri; dark: string | vscode.Uri };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event called when the button is clicked
|
||||||
|
*/
|
||||||
onDidClick: vscode.Event<any>;
|
onDidClick: vscode.Event<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1100,11 +1172,22 @@ declare module 'sqlops' {
|
|||||||
export function createModelViewEditor(title: string, options?: ModelViewEditorOptions): ModelViewEditor;
|
export function createModelViewEditor(title: string, options?: ModelViewEditorOptions): ModelViewEditor;
|
||||||
|
|
||||||
export interface ModelViewEditor extends window.modelviewdialog.ModelViewPanel {
|
export interface ModelViewEditor extends window.modelviewdialog.ModelViewPanel {
|
||||||
|
/**
|
||||||
|
* `true` if there are unpersisted changes.
|
||||||
|
* This is editable to support extensions updating the dirty status.
|
||||||
|
*/
|
||||||
|
isDirty: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the editor
|
* Opens the editor
|
||||||
*/
|
*/
|
||||||
openEditor(position?: vscode.ViewColumn): Thenable<void>;
|
openEditor(position?: vscode.ViewColumn): Thenable<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a save handler for this editor. This will be called if [supportsSave](#ModelViewEditorOptions.supportsSave)
|
||||||
|
* is set to true and the editor is marked as dirty
|
||||||
|
*/
|
||||||
|
registerSaveHandler(handler: () => Thenable<boolean>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1113,6 +1196,11 @@ declare module 'sqlops' {
|
|||||||
* Should the model view editor's context be kept around even when the editor is no longer visible? It is false by default
|
* Should the model view editor's context be kept around even when the editor is no longer visible? It is false by default
|
||||||
*/
|
*/
|
||||||
readonly retainContextWhenHidden?: boolean;
|
readonly retainContextWhenHidden?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this model view editor support save?
|
||||||
|
*/
|
||||||
|
readonly supportsSave?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DataProviderType {
|
export enum DataProviderType {
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ export enum FrequencyRelativeIntervals {
|
|||||||
|
|
||||||
export enum ModelComponentTypes {
|
export enum ModelComponentTypes {
|
||||||
NavContainer,
|
NavContainer,
|
||||||
|
DivContainer,
|
||||||
FlexContainer,
|
FlexContainer,
|
||||||
Card,
|
Card,
|
||||||
InputBox,
|
InputBox,
|
||||||
@@ -151,7 +152,8 @@ export enum ModelComponentTypes {
|
|||||||
LoadingComponent,
|
LoadingComponent,
|
||||||
TreeComponent,
|
TreeComponent,
|
||||||
FileBrowserTree,
|
FileBrowserTree,
|
||||||
Editor
|
Editor,
|
||||||
|
Dom
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IComponentShape {
|
export interface IComponentShape {
|
||||||
|
|||||||
@@ -90,14 +90,16 @@ export class ExtHostAccountManagement extends ExtHostAccountManagementShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public $getSecurityToken(account: sqlops.Account): Thenable<{}> {
|
public $getSecurityToken(account: sqlops.Account): Thenable<{}> {
|
||||||
for (const handle in this._accounts) {
|
return this.$getAllAccounts().then(() => {
|
||||||
const providerHandle = parseInt(handle);
|
for (const handle in this._accounts) {
|
||||||
if (this._accounts[handle].findIndex((acct) => acct.key.accountId === account.key.accountId) !== -1) {
|
const providerHandle = parseInt(handle);
|
||||||
return this._withProvider(providerHandle, (provider: sqlops.AccountProvider) => provider.getSecurityToken(account));
|
if (this._accounts[handle].findIndex((acct) => acct.key.accountId === account.key.accountId) !== -1) {
|
||||||
|
return this._withProvider(providerHandle, (provider: sqlops.AccountProvider) => provider.getSecurityToken(account));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(`Account ${account.key.accountId} not found.`);
|
throw new Error(`Account ${account.key.accountId} not found.`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public get onDidChangeAccounts(): Event<sqlops.DidChangeAccountsParams> {
|
public get onDidChangeAccounts(): Event<sqlops.DidChangeAccountsParams> {
|
||||||
|
|||||||
@@ -32,14 +32,21 @@ class ModelBuilderImpl implements sqlops.ModelBuilder {
|
|||||||
|
|
||||||
navContainer(): sqlops.ContainerBuilder<sqlops.NavContainer, any, any> {
|
navContainer(): sqlops.ContainerBuilder<sqlops.NavContainer, any, any> {
|
||||||
let id = this.getNextComponentId();
|
let id = this.getNextComponentId();
|
||||||
let container: ContainerBuilderImpl<sqlops.NavContainer, any, any> = new ContainerBuilderImpl(this._proxy, this._handle, ModelComponentTypes.NavContainer, id);
|
let container: GenericContainerBuilder<sqlops.NavContainer, any, any> = new GenericContainerBuilder(this._proxy, this._handle, ModelComponentTypes.NavContainer, id);
|
||||||
|
this._componentBuilders.set(id, container);
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
divContainer(): sqlops.DivBuilder {
|
||||||
|
let id = this.getNextComponentId();
|
||||||
|
let container = new DivContainerBuilder(this._proxy, this._handle, ModelComponentTypes.DivContainer, id);
|
||||||
this._componentBuilders.set(id, container);
|
this._componentBuilders.set(id, container);
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
flexContainer(): sqlops.FlexBuilder {
|
flexContainer(): sqlops.FlexBuilder {
|
||||||
let id = this.getNextComponentId();
|
let id = this.getNextComponentId();
|
||||||
let container: ContainerBuilderImpl<sqlops.FlexContainer, any, any> = new ContainerBuilderImpl<sqlops.FlexContainer, sqlops.FlexLayout, sqlops.FlexItemLayout>(this._proxy, this._handle, ModelComponentTypes.FlexContainer, id);
|
let container: GenericContainerBuilder<sqlops.FlexContainer, any, any> = new GenericContainerBuilder<sqlops.FlexContainer, sqlops.FlexLayout, sqlops.FlexItemLayout>(this._proxy, this._handle, ModelComponentTypes.FlexContainer, id);
|
||||||
this._componentBuilders.set(id, container);
|
this._componentBuilders.set(id, container);
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
@@ -60,7 +67,7 @@ class ModelBuilderImpl implements sqlops.ModelBuilder {
|
|||||||
|
|
||||||
groupContainer(): sqlops.GroupBuilder {
|
groupContainer(): sqlops.GroupBuilder {
|
||||||
let id = this.getNextComponentId();
|
let id = this.getNextComponentId();
|
||||||
let container: ContainerBuilderImpl<sqlops.GroupContainer, any, any> = new ContainerBuilderImpl<sqlops.GroupContainer, sqlops.GroupLayout, sqlops.GroupItemLayout>(this._proxy, this._handle, ModelComponentTypes.Group, id);
|
let container: GenericContainerBuilder<sqlops.GroupContainer, any, any> = new GenericContainerBuilder<sqlops.GroupContainer, sqlops.GroupLayout, sqlops.GroupItemLayout>(this._proxy, this._handle, ModelComponentTypes.Group, id);
|
||||||
this._componentBuilders.set(id, container);
|
this._componentBuilders.set(id, container);
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
@@ -184,6 +191,13 @@ class ModelBuilderImpl implements sqlops.ModelBuilder {
|
|||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dom(): sqlops.ComponentBuilder<sqlops.DomComponent> {
|
||||||
|
let id = this.getNextComponentId();
|
||||||
|
let builder: ComponentBuilderImpl<sqlops.DomComponent> = this.getComponentBuilder(new DomComponentWrapper(this._proxy, this._handle, id), id);
|
||||||
|
this._componentBuilders.set(id, builder);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
getComponentBuilder<T extends sqlops.Component>(component: ComponentWrapper, id: string): ComponentBuilderImpl<T> {
|
getComponentBuilder<T extends sqlops.Component>(component: ComponentWrapper, id: string): ComponentBuilderImpl<T> {
|
||||||
let componentBuilder: ComponentBuilderImpl<T> = new ComponentBuilderImpl<T>(component);
|
let componentBuilder: ComponentBuilderImpl<T> = new ComponentBuilderImpl<T>(component);
|
||||||
this._componentBuilders.set(id, componentBuilder);
|
this._componentBuilders.set(id, componentBuilder);
|
||||||
@@ -241,17 +255,9 @@ class ComponentBuilderImpl<T extends sqlops.Component> implements sqlops.Compone
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GenericComponentBuilder<T extends sqlops.Component> extends ComponentBuilderImpl<T> {
|
|
||||||
constructor(proxy: MainThreadModelViewShape, handle: number, type: ModelComponentTypes, id: string) {
|
|
||||||
super(new ComponentWrapper(proxy, handle, type, id));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ContainerBuilderImpl<T extends sqlops.Component, TLayout, TItemLayout> extends ComponentBuilderImpl<T> implements sqlops.ContainerBuilder<T, TLayout, TItemLayout> {
|
class ContainerBuilderImpl<T extends sqlops.Component, TLayout, TItemLayout> extends ComponentBuilderImpl<T> implements sqlops.ContainerBuilder<T, TLayout, TItemLayout> {
|
||||||
constructor(proxy: MainThreadModelViewShape, handle: number, type: ModelComponentTypes, id: string) {
|
constructor(componentWrapper: ComponentWrapper) {
|
||||||
super(new ComponentWrapper(proxy, handle, type, id));
|
super(componentWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
withLayout(layout: TLayout): sqlops.ContainerBuilder<T, TLayout, TItemLayout> {
|
withLayout(layout: TLayout): sqlops.ContainerBuilder<T, TLayout, TItemLayout> {
|
||||||
@@ -268,7 +274,19 @@ class ContainerBuilderImpl<T extends sqlops.Component, TLayout, TItemLayout> ext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FormContainerBuilder extends ContainerBuilderImpl<sqlops.FormContainer, sqlops.FormLayout, sqlops.FormItemLayout> implements sqlops.FormBuilder {
|
class GenericContainerBuilder<T extends sqlops.Component, TLayout, TItemLayout> extends ContainerBuilderImpl<T, TLayout, TItemLayout> {
|
||||||
|
constructor(proxy: MainThreadModelViewShape, handle: number, type: ModelComponentTypes, id: string) {
|
||||||
|
super(new ComponentWrapper(proxy, handle, type, id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DivContainerBuilder extends ContainerBuilderImpl<sqlops.DivContainer, sqlops.DivLayout, sqlops.DivItemLayout> {
|
||||||
|
constructor(proxy: MainThreadModelViewShape, handle: number, type: ModelComponentTypes, id: string) {
|
||||||
|
super(new DivContainerWrapper(proxy, handle, type, id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FormContainerBuilder extends GenericContainerBuilder<sqlops.FormContainer, sqlops.FormLayout, sqlops.FormItemLayout> implements sqlops.FormBuilder {
|
||||||
constructor(proxy: MainThreadModelViewShape, handle: number, type: ModelComponentTypes, id: string, private _builder: ModelBuilderImpl) {
|
constructor(proxy: MainThreadModelViewShape, handle: number, type: ModelComponentTypes, id: string, private _builder: ModelBuilderImpl) {
|
||||||
super(proxy, handle, type, id);
|
super(proxy, handle, type, id);
|
||||||
}
|
}
|
||||||
@@ -376,7 +394,7 @@ class FormContainerBuilder extends ContainerBuilderImpl<sqlops.FormContainer, sq
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ToolbarContainerBuilder extends ContainerBuilderImpl<sqlops.ToolbarContainer, sqlops.ToolbarLayout, any> implements sqlops.ToolbarBuilder {
|
class ToolbarContainerBuilder extends GenericContainerBuilder<sqlops.ToolbarContainer, sqlops.ToolbarLayout, any> implements sqlops.ToolbarBuilder {
|
||||||
withToolbarItems(components: sqlops.ToolbarComponent[]): sqlops.ContainerBuilder<sqlops.ToolbarContainer, any, any> {
|
withToolbarItems(components: sqlops.ToolbarComponent[]): sqlops.ContainerBuilder<sqlops.ToolbarContainer, any, any> {
|
||||||
this._component.itemConfigs = components.map(item => {
|
this._component.itemConfigs = components.map(item => {
|
||||||
return this.convertToItemConfig(item);
|
return this.convertToItemConfig(item);
|
||||||
@@ -829,8 +847,8 @@ class WebViewWrapper extends ComponentWrapper implements sqlops.WebViewComponent
|
|||||||
public get html(): string {
|
public get html(): string {
|
||||||
return this.properties['html'];
|
return this.properties['html'];
|
||||||
}
|
}
|
||||||
public set html(v: string) {
|
public set html(html: string) {
|
||||||
this.setProperty('html', v);
|
this.setProperty('html', html);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get onMessage(): vscode.Event<any> {
|
public get onMessage(): vscode.Event<any> {
|
||||||
@@ -844,9 +862,21 @@ class WebViewWrapper extends ComponentWrapper implements sqlops.WebViewComponent
|
|||||||
public set options(o: vscode.WebviewOptions) {
|
public set options(o: vscode.WebviewOptions) {
|
||||||
this.setProperty('options', o);
|
this.setProperty('options', o);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DomComponentWrapper extends ComponentWrapper implements sqlops.DomComponent {
|
||||||
|
|
||||||
|
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
|
||||||
|
super(proxy, handle, ModelComponentTypes.Dom, id);
|
||||||
|
this.properties = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public get html(): string {
|
||||||
|
return this.properties['html'];
|
||||||
|
}
|
||||||
|
public set html(html: string) {
|
||||||
|
this.setProperty('html', html);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EditorWrapper extends ComponentWrapper implements sqlops.EditorComponent {
|
class EditorWrapper extends ComponentWrapper implements sqlops.EditorComponent {
|
||||||
@@ -1103,6 +1133,13 @@ class ButtonWrapper extends ComponentWrapper implements sqlops.ButtonComponent {
|
|||||||
this.setProperty('iconPath', v);
|
this.setProperty('iconPath', v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get title(): string {
|
||||||
|
return this.properties['title'];
|
||||||
|
}
|
||||||
|
public set title(v: string) {
|
||||||
|
this.setProperty('title', v);
|
||||||
|
}
|
||||||
|
|
||||||
public get onDidClick(): vscode.Event<any> {
|
public get onDidClick(): vscode.Event<any> {
|
||||||
let emitter = this._emitterMap.get(ComponentEventType.onDidClick);
|
let emitter = this._emitterMap.get(ComponentEventType.onDidClick);
|
||||||
return emitter && emitter.event;
|
return emitter && emitter.event;
|
||||||
@@ -1155,6 +1192,24 @@ class FileBrowserTreeComponentWrapper extends ComponentWrapper implements sqlops
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DivContainerWrapper extends ComponentWrapper implements sqlops.DivContainer {
|
||||||
|
public get overflowY(): string {
|
||||||
|
return this.properties['overflowY'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public set overflowY(value: string) {
|
||||||
|
this.setProperty('overflowY', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get yOffsetChange(): number {
|
||||||
|
return this.properties['yOffsetChange'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public set yOffsetChange(value: number) {
|
||||||
|
this.setProperty('yOffsetChange', value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TreeComponentWrapper<T> extends ComponentWrapper implements sqlops.TreeComponent<T> {
|
class TreeComponentWrapper<T> extends ComponentWrapper implements sqlops.TreeComponent<T> {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
@@ -75,6 +75,9 @@ class ModelViewPanelImpl implements sqlops.window.modelviewdialog.ModelViewPanel
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ModelViewEditorImpl extends ModelViewPanelImpl implements sqlops.workspace.ModelViewEditor {
|
class ModelViewEditorImpl extends ModelViewPanelImpl implements sqlops.workspace.ModelViewEditor {
|
||||||
|
private _isDirty: boolean;
|
||||||
|
private _saveHandler: () => Thenable<boolean>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
extHostModelViewDialog: ExtHostModelViewDialog,
|
extHostModelViewDialog: ExtHostModelViewDialog,
|
||||||
extHostModelView: ExtHostModelViewShape,
|
extHostModelView: ExtHostModelViewShape,
|
||||||
@@ -84,10 +87,32 @@ class ModelViewEditorImpl extends ModelViewPanelImpl implements sqlops.workspace
|
|||||||
private _options: sqlops.ModelViewEditorOptions
|
private _options: sqlops.ModelViewEditorOptions
|
||||||
) {
|
) {
|
||||||
super('modelViewEditor', extHostModelViewDialog, extHostModelView, extensionLocation);
|
super('modelViewEditor', extHostModelViewDialog, extHostModelView, extensionLocation);
|
||||||
|
this._isDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public openEditor(position?: vscode.ViewColumn): Thenable<void> {
|
public openEditor(position?: vscode.ViewColumn): Thenable<void> {
|
||||||
return this._proxy.$openEditor(this._modelViewId, this._title, this._options, position);
|
return this._proxy.$openEditor(this.handle, this._modelViewId, this._title, this._options, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isDirty(): boolean {
|
||||||
|
return this._isDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set isDirty(value: boolean) {
|
||||||
|
this._isDirty = value;
|
||||||
|
this._proxy.$setDirty(this.handle, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerSaveHandler(handler: () => Thenable<boolean>) {
|
||||||
|
this._saveHandler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public handleSave(): Thenable<boolean> {
|
||||||
|
if (this._saveHandler) {
|
||||||
|
return Promise.resolve(this._saveHandler());
|
||||||
|
} else {
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,6 +495,11 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape {
|
|||||||
return dialog.validateClose();
|
return dialog.validateClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public $handleSave(handle: number): Thenable<boolean> {
|
||||||
|
let editor = this._objectsByHandle.get(handle) as ModelViewEditorImpl;
|
||||||
|
return editor.handleSave();
|
||||||
|
}
|
||||||
|
|
||||||
public openDialog(dialog: sqlops.window.modelviewdialog.Dialog): void {
|
public openDialog(dialog: sqlops.window.modelviewdialog.Dialog): void {
|
||||||
let handle = this.getHandle(dialog);
|
let handle = this.getHandle(dialog);
|
||||||
this.updateDialogContent(dialog);
|
this.updateDialogContent(dialog);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ExtHostObjectExplorerShape, SqlMainContext, MainThreadObjectExplorerSha
|
|||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
export class ExtHostObjectExplorer implements ExtHostObjectExplorerShape {
|
export class ExtHostObjectExplorer implements ExtHostObjectExplorerShape {
|
||||||
|
|
||||||
private _proxy: MainThreadObjectExplorerShape;
|
private _proxy: MainThreadObjectExplorerShape;
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ class ExtHostObjectExplorerNode implements sqlops.objectexplorer.ObjectExplorerN
|
|||||||
public errorMessage: string;
|
public errorMessage: string;
|
||||||
|
|
||||||
constructor(nodeInfo: sqlops.NodeInfo, connectionId: string, private _proxy: MainThreadObjectExplorerShape) {
|
constructor(nodeInfo: sqlops.NodeInfo, connectionId: string, private _proxy: MainThreadObjectExplorerShape) {
|
||||||
Object.entries(nodeInfo).forEach(([key, value]) => this[key] = value);
|
this.getDetailsFromInfo(nodeInfo);
|
||||||
this.connectionId = connectionId;
|
this.connectionId = connectionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,4 +71,12 @@ class ExtHostObjectExplorerNode implements sqlops.objectexplorer.ObjectExplorerN
|
|||||||
}
|
}
|
||||||
return this._proxy.$getNode(this.connectionId, this.nodePath.slice(0, parentPathEndIndex)).then(nodeInfo => nodeInfo ? new ExtHostObjectExplorerNode(nodeInfo, this.connectionId, this._proxy) : undefined);
|
return this._proxy.$getNode(this.connectionId, this.nodePath.slice(0, parentPathEndIndex)).then(nodeInfo => nodeInfo ? new ExtHostObjectExplorerNode(nodeInfo, this.connectionId, this._proxy) : undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refresh(): Thenable<void> {
|
||||||
|
return this._proxy.$refresh(this.connectionId, this.nodePath).then(nodeInfo => this.getDetailsFromInfo(nodeInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
private getDetailsFromInfo(nodeInfo: sqlops.NodeInfo): void {
|
||||||
|
Object.entries(nodeInfo).forEach(([key, value]) => this[key] = value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { IEditorOptions } from 'vs/platform/editor/common/editor';
|
import { IEditorOptions } from 'vs/platform/editor/common/editor';
|
||||||
|
import { IEditor } from 'vs/workbench/common/editor';
|
||||||
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
|
||||||
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
|
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
@@ -14,7 +15,7 @@ import { MainThreadModelViewDialogShape, SqlMainContext, ExtHostModelViewDialogS
|
|||||||
import { Dialog, DialogTab, DialogButton, WizardPage, Wizard } from 'sql/platform/dialog/dialogTypes';
|
import { Dialog, DialogTab, DialogButton, WizardPage, Wizard } from 'sql/platform/dialog/dialogTypes';
|
||||||
import { CustomDialogService } from 'sql/platform/dialog/customDialogService';
|
import { CustomDialogService } from 'sql/platform/dialog/customDialogService';
|
||||||
import { IModelViewDialogDetails, IModelViewTabDetails, IModelViewButtonDetails, IModelViewWizardPageDetails, IModelViewWizardDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { IModelViewDialogDetails, IModelViewTabDetails, IModelViewButtonDetails, IModelViewWizardPageDetails, IModelViewWizardDetails } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
import { ModelViewInput } from 'sql/parts/modelComponents/modelEditor/modelViewInput';
|
import { ModelViewInput, ModelViewInputModel, ModeViewSaveHandler } from 'sql/parts/modelComponents/modelEditor/modelViewInput';
|
||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
@@ -28,6 +29,7 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
|||||||
private readonly _wizardPages = new Map<number, WizardPage>();
|
private readonly _wizardPages = new Map<number, WizardPage>();
|
||||||
private readonly _wizardPageHandles = new Map<WizardPage, number>();
|
private readonly _wizardPageHandles = new Map<WizardPage, number>();
|
||||||
private readonly _wizards = new Map<number, Wizard>();
|
private readonly _wizards = new Map<number, Wizard>();
|
||||||
|
private readonly _editorInputModels = new Map<number, ModelViewInputModel>();
|
||||||
private _dialogService: CustomDialogService;
|
private _dialogService: CustomDialogService;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -43,15 +45,18 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
|||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public $openEditor(modelViewId: string, title: string, options?: sqlops.ModelViewEditorOptions, position?: vscode.ViewColumn): Thenable<void> {
|
public $openEditor(handle: number, modelViewId: string, title: string, options?: sqlops.ModelViewEditorOptions, position?: vscode.ViewColumn): Thenable<void> {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
let input = this._instatiationService.createInstance(ModelViewInput, title, modelViewId, options);
|
let saveHandler: ModeViewSaveHandler = options && options.supportsSave ? (h) => this.handleSave(h) : undefined;
|
||||||
|
let model = new ModelViewInputModel(modelViewId, handle, saveHandler);
|
||||||
|
let input = this._instatiationService.createInstance(ModelViewInput, title, model, options);
|
||||||
let editorOptions = {
|
let editorOptions = {
|
||||||
preserveFocus: true,
|
preserveFocus: true,
|
||||||
pinned: true
|
pinned: true
|
||||||
};
|
};
|
||||||
|
|
||||||
this._editorService.openEditor(input, editorOptions, position as any).then(() => {
|
this._editorService.openEditor(input, editorOptions, position as any).then((editor) => {
|
||||||
|
this._editorInputModels.set(handle, model);
|
||||||
resolve();
|
resolve();
|
||||||
}, error => {
|
}, error => {
|
||||||
reject(error);
|
reject(error);
|
||||||
@@ -59,6 +64,10 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleSave(handle: number): Thenable<boolean> {
|
||||||
|
return this._proxy.$handleSave(handle);
|
||||||
|
}
|
||||||
|
|
||||||
public $openDialog(handle: number): Thenable<void> {
|
public $openDialog(handle: number): Thenable<void> {
|
||||||
let dialog = this.getDialog(handle);
|
let dialog = this.getDialog(handle);
|
||||||
this._dialogService.showDialog(dialog);
|
this._dialogService.showDialog(dialog);
|
||||||
@@ -213,6 +222,21 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$setDirty(handle: number, isDirty: boolean): void {
|
||||||
|
let model = this.getEditor(handle);
|
||||||
|
if (model) {
|
||||||
|
model.setDirty(isDirty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getEditor(handle: number): ModelViewInputModel {
|
||||||
|
let model = this._editorInputModels.get(handle);
|
||||||
|
if (!model) {
|
||||||
|
throw new Error('No editor matching the given handle');
|
||||||
|
}
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
private getDialog(handle: number): Dialog {
|
private getDialog(handle: number): Dialog {
|
||||||
let dialog = this._dialogs.get(handle);
|
let dialog = this._dialogs.get(handle);
|
||||||
if (!dialog) {
|
if (!dialog) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
|||||||
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
|
||||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { TreeItemCollapsibleState } from 'sql/parts/objectExplorer/common/treeNode';
|
||||||
|
|
||||||
@extHostNamedCustomer(SqlMainContext.MainThreadObjectExplorer)
|
@extHostNamedCustomer(SqlMainContext.MainThreadObjectExplorer)
|
||||||
export class MainThreadObjectExplorer implements MainThreadObjectExplorerShape {
|
export class MainThreadObjectExplorer implements MainThreadObjectExplorerShape {
|
||||||
@@ -50,7 +51,7 @@ export class MainThreadObjectExplorer implements MainThreadObjectExplorerShape {
|
|||||||
public $getActiveConnectionNodes(): Thenable<NodeInfoWithConnection[]> {
|
public $getActiveConnectionNodes(): Thenable<NodeInfoWithConnection[]> {
|
||||||
let connectionNodes = this._objectExplorerService.getActiveConnectionNodes();
|
let connectionNodes = this._objectExplorerService.getActiveConnectionNodes();
|
||||||
return Promise.resolve(connectionNodes.map(node => {
|
return Promise.resolve(connectionNodes.map(node => {
|
||||||
return {connectionId: node.connection.id, nodeInfo: node.toNodeInfo()};
|
return { connectionId: node.connection.id, nodeInfo: node.toNodeInfo() };
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,4 +74,8 @@ export class MainThreadObjectExplorer implements MainThreadObjectExplorerShape {
|
|||||||
public $findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames: string[]): Thenable<sqlops.NodeInfo[]> {
|
public $findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames: string[]): Thenable<sqlops.NodeInfo[]> {
|
||||||
return this._objectExplorerService.findNodes(connectionId, type, schema, name, database, parentObjectNames);
|
return this._objectExplorerService.findNodes(connectionId, type, schema, name, database, parentObjectNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public $refresh(connectionId: string, nodePath: string): Thenable<sqlops.NodeInfo> {
|
||||||
|
return this._objectExplorerService.refreshNodeInView(connectionId, nodePath).then(node => node.toNodeInfo());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export abstract class ExtHostAccountManagementShape {
|
|||||||
|
|
||||||
export abstract class ExtHostConnectionManagementShape {
|
export abstract class ExtHostConnectionManagementShape {
|
||||||
$onConnectionOpened(handleId: string, connection: sqlops.connection.Connection): void { throw ni; }
|
$onConnectionOpened(handleId: string, connection: sqlops.connection.Connection): void { throw ni; }
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class ExtHostDataProtocolShape {
|
export abstract class ExtHostDataProtocolShape {
|
||||||
|
|
||||||
@@ -663,6 +663,7 @@ export interface MainThreadObjectExplorerShape extends IDisposable {
|
|||||||
$getChildren(connectionId: string, nodePath: string): Thenable<sqlops.NodeInfo[]>;
|
$getChildren(connectionId: string, nodePath: string): Thenable<sqlops.NodeInfo[]>;
|
||||||
$isExpanded(connectionId: string, nodePath: string): Thenable<boolean>;
|
$isExpanded(connectionId: string, nodePath: string): Thenable<boolean>;
|
||||||
$findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames: string[]): Thenable<sqlops.NodeInfo[]>;
|
$findNodes(connectionId: string, type: string, schema: string, name: string, database: string, parentObjectNames: string[]): Thenable<sqlops.NodeInfo[]>;
|
||||||
|
$refresh(connectionId: string, nodePath: string): Thenable<sqlops.NodeInfo>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtHostModelViewDialogShape {
|
export interface ExtHostModelViewDialogShape {
|
||||||
@@ -672,10 +673,11 @@ export interface ExtHostModelViewDialogShape {
|
|||||||
$updateWizardPageInfo(handle: number, pageHandles: number[], currentPageIndex: number): void;
|
$updateWizardPageInfo(handle: number, pageHandles: number[], currentPageIndex: number): void;
|
||||||
$validateNavigation(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): Thenable<boolean>;
|
$validateNavigation(handle: number, info: sqlops.window.modelviewdialog.WizardPageChangeInfo): Thenable<boolean>;
|
||||||
$validateDialogClose(handle: number): Thenable<boolean>;
|
$validateDialogClose(handle: number): Thenable<boolean>;
|
||||||
|
$handleSave(handle: number): Thenable<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MainThreadModelViewDialogShape extends IDisposable {
|
export interface MainThreadModelViewDialogShape extends IDisposable {
|
||||||
$openEditor(modelViewId: string, title: string, options?: sqlops.ModelViewEditorOptions, position?: vscode.ViewColumn): Thenable<void>;
|
$openEditor(handle: number, modelViewId: string, title: string, options?: sqlops.ModelViewEditorOptions, position?: vscode.ViewColumn): Thenable<void>;
|
||||||
$openDialog(handle: number): Thenable<void>;
|
$openDialog(handle: number): Thenable<void>;
|
||||||
$closeDialog(handle: number): Thenable<void>;
|
$closeDialog(handle: number): Thenable<void>;
|
||||||
$setDialogDetails(handle: number, details: IModelViewDialogDetails): Thenable<void>;
|
$setDialogDetails(handle: number, details: IModelViewDialogDetails): Thenable<void>;
|
||||||
@@ -688,6 +690,7 @@ export interface MainThreadModelViewDialogShape extends IDisposable {
|
|||||||
$addWizardPage(wizardHandle: number, pageHandle: number, pageIndex: number): Thenable<void>;
|
$addWizardPage(wizardHandle: number, pageHandle: number, pageIndex: number): Thenable<void>;
|
||||||
$removeWizardPage(wizardHandle: number, pageIndex: number): Thenable<void>;
|
$removeWizardPage(wizardHandle: number, pageIndex: number): Thenable<void>;
|
||||||
$setWizardPage(wizardHandle: number, pageIndex: number): Thenable<void>;
|
$setWizardPage(wizardHandle: number, pageIndex: number): Thenable<void>;
|
||||||
|
$setDirty(handle: number, isDirty: boolean): void;
|
||||||
}
|
}
|
||||||
export interface ExtHostQueryEditorShape {
|
export interface ExtHostQueryEditorShape {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ import { ShowCurrentReleaseNotesAction } from 'sql/workbench/update/releaseNotes
|
|||||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||||
import { IConfigurationRegistry, Extensions as ConfigExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
import { IConfigurationRegistry, Extensions as ConfigExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
|
|
||||||
new Actions.BackupAction().registerTask(false);
|
new Actions.BackupAction().registerTask();
|
||||||
new Actions.RestoreAction().registerTask(false);
|
new Actions.RestoreAction().registerTask();
|
||||||
new Actions.NewQueryAction().registerTask();
|
new Actions.NewQueryAction().registerTask();
|
||||||
new Actions.ConfigureDashboardAction().registerTask();
|
new Actions.ConfigureDashboardAction().registerTask();
|
||||||
|
|
||||||
|
|||||||
@@ -302,6 +302,12 @@ export class BackupAction extends Task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
runTask(accessor: ServicesAccessor, profile: IConnectionProfile): TPromise<void> {
|
runTask(accessor: ServicesAccessor, profile: IConnectionProfile): TPromise<void> {
|
||||||
|
if (!profile) {
|
||||||
|
let objectExplorerService = accessor.get<IObjectExplorerService>(IObjectExplorerService);
|
||||||
|
let connectionManagementService = accessor.get<IConnectionManagementService>(IConnectionManagementService);
|
||||||
|
let workbenchEditorService = accessor.get<IEditorService>(IEditorService);
|
||||||
|
profile = TaskUtilities.getCurrentGlobalConnection(objectExplorerService, connectionManagementService, workbenchEditorService);
|
||||||
|
}
|
||||||
let configurationService = accessor.get<IWorkspaceConfigurationService>(IWorkspaceConfigurationService);
|
let configurationService = accessor.get<IWorkspaceConfigurationService>(IWorkspaceConfigurationService);
|
||||||
let previewFeaturesEnabled: boolean = configurationService.getValue('workbench')['enablePreviewFeatures'];
|
let previewFeaturesEnabled: boolean = configurationService.getValue('workbench')['enablePreviewFeatures'];
|
||||||
if (!previewFeaturesEnabled) {
|
if (!previewFeaturesEnabled) {
|
||||||
@@ -435,7 +441,7 @@ export class NewDatabaseAction extends Action {
|
|||||||
|
|
||||||
export class ConfigureDashboardAction extends Task {
|
export class ConfigureDashboardAction extends Task {
|
||||||
public static readonly ID = 'configureDashboard';
|
public static readonly ID = 'configureDashboard';
|
||||||
public static readonly LABEL = nls.localize('configureDashboard', 'Configure');
|
public static readonly LABEL = nls.localize('configureDashboard', 'Learn How To Configure The Dashboard');
|
||||||
public static readonly ICON = 'configure-dashboard';
|
public static readonly ICON = 'configure-dashboard';
|
||||||
private static readonly configHelpUri = 'https://aka.ms/sqldashboardconfig';
|
private static readonly configHelpUri = 'https://aka.ms/sqldashboardconfig';
|
||||||
|
|
||||||
|
|||||||
@@ -108,13 +108,13 @@ export class ErrorMessageDialog extends Modal {
|
|||||||
private updateIconTitle(): void {
|
private updateIconTitle(): void {
|
||||||
switch (this._severity) {
|
switch (this._severity) {
|
||||||
case Severity.Error:
|
case Severity.Error:
|
||||||
this.titleIconClassName = 'icon error';
|
this.titleIconClassName = 'sql icon error';
|
||||||
break;
|
break;
|
||||||
case Severity.Warning:
|
case Severity.Warning:
|
||||||
this.titleIconClassName = 'icon warning';
|
this.titleIconClassName = 'sql icon warning';
|
||||||
break;
|
break;
|
||||||
case Severity.Info:
|
case Severity.Info:
|
||||||
this.titleIconClassName = 'icon info';
|
this.titleIconClassName = 'sql icon info';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -301,7 +301,8 @@ suite('SQL Object Explorer Service tests', () => {
|
|||||||
reveal: element => Promise.resolve() as Thenable<void>,
|
reveal: element => Promise.resolve() as Thenable<void>,
|
||||||
setSelected: (element, selected, clearOtherSelections) => undefined,
|
setSelected: (element, selected, clearOtherSelections) => undefined,
|
||||||
isExpanded: element => undefined,
|
isExpanded: element => undefined,
|
||||||
onSelectionOrFocusChange: Event.None
|
onSelectionOrFocusChange: Event.None,
|
||||||
|
refreshElement: (element) => Promise.resolve() as Thenable<void>
|
||||||
} as ServerTreeView);
|
} as ServerTreeView);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -738,4 +739,22 @@ suite('SQL Object Explorer Service tests', () => {
|
|||||||
}, err => done(err));
|
}, err => done(err));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('refreshInView refreshes the node, expands it, and returns the refreshed node', async () => {
|
||||||
|
// Set up the session and tree view
|
||||||
|
await objectExplorerService.createNewSession('MSSQL', connection);
|
||||||
|
objectExplorerService.onSessionCreated(1, objectExplorerSession);
|
||||||
|
serverTreeView.setup(x => x.refreshElement(TypeMoq.It.isAny())).returns(() => Promise.resolve());
|
||||||
|
objectExplorerService.registerServerTreeView(serverTreeView.object);
|
||||||
|
|
||||||
|
// Refresh the node
|
||||||
|
let nodePath = objectExplorerSession.rootNode.nodePath;
|
||||||
|
let refreshedNode = await objectExplorerService.refreshNodeInView(connection.id, nodePath);
|
||||||
|
|
||||||
|
// Verify that it was refreshed, expanded, and the refreshed detailed were returned
|
||||||
|
sqlOEProvider.verify(x => x.refreshNode(TypeMoq.It.is(refreshNode => refreshNode.nodePath === nodePath)), TypeMoq.Times.once());
|
||||||
|
refreshedNode.children.forEach((childNode, index) => {
|
||||||
|
assert.equal(childNode.nodePath, objectExplorerExpandInfoRefresh.nodes[index].nodePath);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -28,6 +28,7 @@ import { ConnectionManagementService } from 'sql/parts/connection/common/connect
|
|||||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||||
|
|
||||||
import { TestThemeService } from 'sqltest/stubs/themeTestService';
|
import { TestThemeService } from 'sqltest/stubs/themeTestService';
|
||||||
|
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
|
||||||
|
|
||||||
import * as TypeMoq from 'typemoq';
|
import * as TypeMoq from 'typemoq';
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
@@ -40,6 +41,7 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
let editor: TypeMoq.Mock<QueryEditor>;
|
let editor: TypeMoq.Mock<QueryEditor>;
|
||||||
let calledRunQueryOnInput: boolean = undefined;
|
let calledRunQueryOnInput: boolean = undefined;
|
||||||
let testQueryInput: TypeMoq.Mock<QueryInput>;
|
let testQueryInput: TypeMoq.Mock<QueryInput>;
|
||||||
|
let configurationService: TypeMoq.Mock<ConfigurationService>;
|
||||||
|
|
||||||
setup(() => {
|
setup(() => {
|
||||||
// Setup a reusable mock QueryInput
|
// Setup a reusable mock QueryInput
|
||||||
@@ -56,6 +58,13 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
editor.setup(x => x.getSelection()).returns(() => undefined);
|
editor.setup(x => x.getSelection()).returns(() => undefined);
|
||||||
editor.setup(x => x.getSelection(false)).returns(() => undefined);
|
editor.setup(x => x.getSelection(false)).returns(() => undefined);
|
||||||
editor.setup(x => x.isSelectionEmpty()).returns(() => false);
|
editor.setup(x => x.isSelectionEmpty()).returns(() => false);
|
||||||
|
configurationService = TypeMoq.Mock.ofInstance({
|
||||||
|
getValue: () => undefined,
|
||||||
|
onDidChangeConfiguration: () => undefined
|
||||||
|
} as any);
|
||||||
|
configurationService.setup(x => x.getValue(TypeMoq.It.isAny())).returns(() => {
|
||||||
|
return {};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('setClass sets child CSS class correctly', (done) => {
|
test('setClass sets child CSS class correctly', (done) => {
|
||||||
@@ -463,7 +472,7 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// If I query without having initialized anything, state should be clear
|
// If I query without having initialized anything, state should be clear
|
||||||
listItem = new ListDatabasesActionItem(editor.object, undefined, connectionManagementService.object, undefined, undefined, undefined);
|
listItem = new ListDatabasesActionItem(editor.object, undefined, connectionManagementService.object, undefined, undefined, undefined, configurationService.object);
|
||||||
|
|
||||||
assert.equal(listItem.isEnabled(), false, 'do not expect dropdown enabled unless connected');
|
assert.equal(listItem.isEnabled(), false, 'do not expect dropdown enabled unless connected');
|
||||||
assert.equal(listItem.currentDatabaseName, undefined, 'do not expect dropdown to have entries unless connected');
|
assert.equal(listItem.currentDatabaseName, undefined, 'do not expect dropdown to have entries unless connected');
|
||||||
@@ -498,7 +507,7 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
cms.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{ databaseName: databaseName });
|
cms.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{ databaseName: databaseName });
|
||||||
|
|
||||||
// ... Create a database dropdown that has been connected
|
// ... Create a database dropdown that has been connected
|
||||||
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, null, null, null);
|
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, null, null, null, configurationService.object);
|
||||||
listItem.onConnected();
|
listItem.onConnected();
|
||||||
|
|
||||||
// If: I raise a connection changed event
|
// If: I raise a connection changed event
|
||||||
@@ -522,7 +531,7 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
cms.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{ databaseName: databaseName });
|
cms.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{ databaseName: databaseName });
|
||||||
|
|
||||||
// ... Create a database dropdown that has been connected
|
// ... Create a database dropdown that has been connected
|
||||||
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, null, null, null);
|
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, null, null, null, configurationService.object);
|
||||||
listItem.onConnected();
|
listItem.onConnected();
|
||||||
|
|
||||||
// If: I raise a connection changed event for the 'wrong' URI
|
// If: I raise a connection changed event for the 'wrong' URI
|
||||||
@@ -549,7 +558,7 @@ suite('SQL QueryAction Tests', () => {
|
|||||||
cms.setup(x => x.onConnectionChanged).returns(() => dbChangedEmitter.event);
|
cms.setup(x => x.onConnectionChanged).returns(() => dbChangedEmitter.event);
|
||||||
|
|
||||||
// ... Create a database dropdown
|
// ... Create a database dropdown
|
||||||
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, null, null, null);
|
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, null, null, null, configurationService.object);
|
||||||
|
|
||||||
// If: I raise a connection changed event
|
// If: I raise a connection changed event
|
||||||
let eventParams = <IConnectionParams>{
|
let eventParams = <IConnectionParams>{
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ suite('SQL QueryEditor Tests', () => {
|
|||||||
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns((classDef, editor, action) => {
|
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns((classDef, editor, action) => {
|
||||||
if (classDef.ID) {
|
if (classDef.ID) {
|
||||||
if (classDef.ID === 'listDatabaseQueryActionItem') {
|
if (classDef.ID === 'listDatabaseQueryActionItem') {
|
||||||
return new ListDatabasesActionItem(editor, action, connectionManagementService.object, undefined, undefined, undefined);
|
return new ListDatabasesActionItem(editor, action, connectionManagementService.object, undefined, undefined, undefined, configurationService.object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Default
|
// Default
|
||||||
@@ -110,18 +110,26 @@ suite('SQL QueryEditor Tests', () => {
|
|||||||
editorDescriptorService = TypeMoq.Mock.ofType(EditorDescriptorService, TypeMoq.MockBehavior.Loose);
|
editorDescriptorService = TypeMoq.Mock.ofType(EditorDescriptorService, TypeMoq.MockBehavior.Loose);
|
||||||
editorDescriptorService.setup(x => x.getEditor(TypeMoq.It.isAny())).returns(() => descriptor);
|
editorDescriptorService.setup(x => x.getEditor(TypeMoq.It.isAny())).returns(() => descriptor);
|
||||||
|
|
||||||
|
configurationService = TypeMoq.Mock.ofInstance({
|
||||||
|
getValue: () => undefined,
|
||||||
|
onDidChangeConfiguration: () => undefined
|
||||||
|
} as any);
|
||||||
|
configurationService.setup(x => x.getValue(TypeMoq.It.isAny())).returns(() => {
|
||||||
|
return { enablePreviewFeatures: true };
|
||||||
|
});
|
||||||
|
|
||||||
// Create a QueryInput
|
// Create a QueryInput
|
||||||
let filePath = 'someFile.sql';
|
let filePath = 'someFile.sql';
|
||||||
let uri: URI = URI.parse(filePath);
|
let uri: URI = URI.parse(filePath);
|
||||||
let fileInput = new UntitledEditorInput(uri, false, '', '', '', instantiationService.object, undefined, undefined, undefined);
|
let fileInput = new UntitledEditorInput(uri, false, '', '', '', instantiationService.object, undefined, undefined, undefined);
|
||||||
let queryResultsInput: QueryResultsInput = new QueryResultsInput(uri.fsPath);
|
let queryResultsInput: QueryResultsInput = new QueryResultsInput(uri.fsPath, configurationService.object);
|
||||||
queryInput = new QueryInput('first', fileInput, queryResultsInput, undefined, undefined, undefined, undefined, undefined);
|
queryInput = new QueryInput('first', fileInput, queryResultsInput, undefined, undefined, undefined, undefined, undefined);
|
||||||
|
|
||||||
// Create a QueryInput to compare to the previous one
|
// Create a QueryInput to compare to the previous one
|
||||||
let filePath2 = 'someFile2.sql';
|
let filePath2 = 'someFile2.sql';
|
||||||
let uri2: URI = URI.parse(filePath2);
|
let uri2: URI = URI.parse(filePath2);
|
||||||
let fileInput2 = new UntitledEditorInput(uri2, false, '', '', '', instantiationService.object, undefined, undefined, undefined);
|
let fileInput2 = new UntitledEditorInput(uri2, false, '', '', '', instantiationService.object, undefined, undefined, undefined);
|
||||||
let queryResultsInput2: QueryResultsInput = new QueryResultsInput(uri2.fsPath);
|
let queryResultsInput2: QueryResultsInput = new QueryResultsInput(uri2.fsPath, configurationService.object);
|
||||||
queryInput2 = new QueryInput('second', fileInput2, queryResultsInput2, undefined, undefined, undefined, undefined, undefined);
|
queryInput2 = new QueryInput('second', fileInput2, queryResultsInput2, undefined, undefined, undefined, undefined, undefined);
|
||||||
|
|
||||||
// Mock IMessageService
|
// Mock IMessageService
|
||||||
@@ -136,14 +144,6 @@ suite('SQL QueryEditor Tests', () => {
|
|||||||
|
|
||||||
// Create a QueryModelService
|
// Create a QueryModelService
|
||||||
queryModelService = new QueryModelService(instantiationService.object, notificationService.object);
|
queryModelService = new QueryModelService(instantiationService.object, notificationService.object);
|
||||||
|
|
||||||
configurationService = TypeMoq.Mock.ofInstance({
|
|
||||||
getValue: () => undefined,
|
|
||||||
onDidChangeConfiguration: () => undefined
|
|
||||||
} as any);
|
|
||||||
configurationService.setup(x => x.getValue(TypeMoq.It.isAny())).returns(() => {
|
|
||||||
return { enablePreviewFeatures: true };
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('createEditor creates only the taskbar', (done) => {
|
test('createEditor creates only the taskbar', (done) => {
|
||||||
@@ -344,7 +344,7 @@ suite('SQL QueryEditor Tests', () => {
|
|||||||
queryActionInstantiationService.setup(x => x.createInstance(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()))
|
queryActionInstantiationService.setup(x => x.createInstance(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()))
|
||||||
.returns((definition, editor, action, selectBox) => {
|
.returns((definition, editor, action, selectBox) => {
|
||||||
if (definition.ID === 'listDatabaseQueryActionItem') {
|
if (definition.ID === 'listDatabaseQueryActionItem') {
|
||||||
let item = new ListDatabasesActionItem(editor, action, queryConnectionService.object, undefined, undefined, undefined);
|
let item = new ListDatabasesActionItem(editor, action, queryConnectionService.object, undefined, undefined, undefined,configurationService.object);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
// Default
|
// Default
|
||||||
@@ -393,7 +393,7 @@ suite('SQL QueryEditor Tests', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
test('Test that we attempt to dispose query when the queryInput is disposed', (done) => {
|
test('Test that we attempt to dispose query when the queryInput is disposed', (done) => {
|
||||||
let queryResultsInput = new QueryResultsInput('testUri');
|
let queryResultsInput = new QueryResultsInput('testUri', configurationService.object);
|
||||||
queryInput['_results'] = queryResultsInput;
|
queryInput['_results'] = queryResultsInput;
|
||||||
queryInput.dispose();
|
queryInput.dispose();
|
||||||
queryModelService.verify(x => x.disposeQuery(TypeMoq.It.isAnyString()), TypeMoq.Times.once());
|
queryModelService.verify(x => x.disposeQuery(TypeMoq.It.isAnyString()), TypeMoq.Times.once());
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user