Compare commits

..

71 Commits

Author SHA1 Message Date
Matt Irvine
05040425df Add OE node refresh API method (#2578)
* Initial working commit for refreshing OE node via API

* Add test and fix up code

* Run tsfmt

* Fix test
2018-09-13 18:43:47 -07:00
Alan Ren
36f7c283b8 use latest slickgrid library (#2584) 2018-09-13 18:43:06 -07:00
Anthony Dresser
9fe4237033 Maintain Query State (#2571)
* add results view stating

* working through the bugs

* handle various resizing bugs

* gnale resizing better

* fix tests by adding missing node module

* formatting

* refactor interfaces out to get around testing restrictions

* more refactoring of importants to avoid loading errors
2018-09-13 18:42:29 -07:00
Alan Ren
b03c0a3e2d accessibility setting based select database dropdown (#2579) 2018-09-13 15:07:08 -07:00
Aditya Bist
87946996ed added context to chart buttons so they work (#2575) 2018-09-13 14:22:57 -07:00
AlexFsmn
cc55023440 Disabled connection name input when connecting to a server. (#2566)
* Disabled connection name input when connecting to a server.
#2557

* Fixed reset state of connection inputs
2018-09-13 12:36:28 -07:00
Karl Burtram
1f19dfc50d Update SQL Ops to 0.33.5 2018-09-13 08:06:27 -07:00
Alan Ren
950a440350 fix the connection issue when opening new query after connection (#2561) 2018-09-13 08:05:46 -07:00
Aditya Bist
c92b88bfaf Bug/extension contribution (#2560)
* revert 4ab5d84b94

* fixed extensions
2018-09-12 23:04:59 -07:00
Abbie Petchtes
10875f26dc add divcontainer in modelview (#2559)
* add divcontainer in modelview

* address comment
2018-09-12 20:18:40 -07:00
Kevin Cunnane
d62e809c18 Support isDirty flag for model view editors and begin plumb through of save support (#2547)
* Add dirty and save support to model view

* Add issue # for a TODO
2018-09-12 14:35:19 -07:00
Alan Ren
d85bf4f6dd fix the account not found error when creating firewall rules (#2543) 2018-09-12 13:32:40 -07:00
Anthony Dresser
801e201cc3 change active cell during change to fix focus shift (#2545) 2018-09-12 13:22:01 -07:00
Anthony Dresser
e18e0da0c1 Fix sizing error when switching windows (#2544)
* add work around for when we need to resize while we don't have a dimension to resize off of

* formatting
2018-09-12 13:21:51 -07:00
Karl Burtram
d046b0a412 Update SQL Ops to 0.33.4 2018-09-12 13:09:41 -07:00
Karl Burtram
72084b8fc1 Fix build break in Git extension (#2538) 2018-09-11 21:48:44 -07:00
Anthony Dresser
2639b2bd2c Fix bug around debounced event not being flushed in time (#2536)
* fix bug around debounced event not being flushed in time

* add comment
2018-09-11 21:22:25 -07:00
Anthony Dresser
82aa493dfd Reduce message panel min size to 0 (#2534)
* reduce message panel minimum size to 0; attempt to restore panel sizing on requery sizes; default grid panel size to 80%

* formatting
2018-09-11 21:22:06 -07:00
Karl Burtram
6c3c7c40b5 Turn-off Git missing prompt (#2533) 2018-09-11 21:21:44 -07:00
Anthony Dresser
5616751c04 fix grid action bar not updating (#2532) 2018-09-11 21:21:30 -07:00
Anthony Dresser
7d898ca34d Fix grid gaps (#2531)
* modifying grid gaps

* reduce gaps and increase gap for action bar
2018-09-11 21:21:06 -07:00
Kevin Cunnane
e26556b21a Fixes #2523 (#2528)
The IdGenerator was recreated each time and had a high likelihood of conflicts. Invitably after adding dozens or hundreds of icons you'll start seeing the CSS class replaced and overridden.

The solution is to do like elsewhere: have 1 const that is loaded on first import of the file and keeps a global track.

Side note is that it'd be a good idea to cache CSS rules with the same iconPath so we don't create lots of additional rules unnecessarily. If we reuse the same icon a bunch we should cache them - #2524 is tracking this.
2018-09-11 21:20:38 -07:00
Anthony Dresser
89e6d363e2 Selection in grid context (#2527)
* update action context on selection change

* correctly add ranges rather than a new range for every row

* add required functions to typings
2018-09-11 17:10:53 -07:00
Anthony Dresser
c559ac7be9 expand messages panel on error (#2519) 2018-09-11 17:09:40 -07:00
Anthony Dresser
b3fbe47f0a add min size for row num column (#2518) 2018-09-11 17:09:17 -07:00
Anthony Dresser
c73af4c480 add check for selection model in edit data (#2517) 2018-09-11 17:08:41 -07:00
Alan Ren
8887fe1eac fix the save and save all for untitled file (#2526) 2018-09-11 17:06:28 -07:00
Kevin Cunnane
ed861a6c96 Revert "Fixes #2523" (#2525)
This reverts commit e63bb6a8ec.
2018-09-11 16:42:27 -07:00
Kevin Cunnane
e63bb6a8ec Fixes #2523
The IdGenerator was recreated each time and had a high likelihood of conflicts. Invitably after adding dozens or hundreds of icons you'll start seeing the CSS class replaced and overridden.

The solution is to do like elsewhere: have 1 const that is loaded on first import of the file and keeps a global track.

Side note is that it'd be a good idea to cache CSS rules with the same iconPath so we don't create lots of additional rules unnecessarily. If we reuse the same icon a bunch we should cache them - #2524 is tracking this.
2018-09-11 16:36:17 -07:00
Anthony Dresser
8ec09d25ce add listener to change action bar on maximize change (#2505) 2018-09-11 12:42:06 -07:00
Anthony Dresser
a9a01ae479 fixes a rendering problem in splitview (#2512) 2018-09-11 12:18:03 -07:00
Karl Burtram
31a3864789 Disable the User Setup prompt (#2501) 2018-09-11 11:52:04 -07:00
Abbie Petchtes
a5c537197c add animation when button is clicked and fix title in button (#2488)
* add animation similar to toolbar in vscode and fix title in button

* remove bur method in button
2018-09-11 10:37:02 -07:00
Anthony Dresser
4ea13bdbc0 add select all handler to grid (#2496) 2018-09-10 21:18:39 -07:00
Anthony Dresser
b06ddf2dc7 change cursor in message panel to default (#2494) 2018-09-10 21:18:18 -07:00
Karl Burtram
2c45ac9df3 Reorder Connection Name field in Connection Dialog (#2498) 2018-09-10 21:17:57 -07:00
Anthony Dresser
7735f68502 Add check for potential failure in handling drag (#2499)
* add check for potential failure in handling drag

* move check to avoid ui glitches
2018-09-10 21:17:42 -07:00
Anthony Dresser
ffb0f5a1c7 add grid styles (#2483) 2018-09-10 21:17:26 -07:00
Anthony Dresser
80c7f9e855 add logic to hide and add grid panel based on size (#2481) 2018-09-10 21:16:54 -07:00
Alan Ren
709ef4e39f Alanren/icon overwrite issue (#2484)
* fix the error icon too large issue

* formatting
2018-09-10 15:55:40 -07:00
Anthony Dresser
4ceb869420 remove autosize and change column header css to properly respect column sizes (#2480) 2018-09-10 14:59:32 -07:00
Anthony Dresser
432a209184 fix error message formatting (#2477) 2018-09-10 14:58:51 -07:00
Karl Burtram
8444271c58 Fix Action Bar viewlet ordering (#2472) 2018-09-09 19:58:27 -07:00
Karl Burtram
2bc97c23d4 Bump Electron to 2.0.8 and SQL Ops to 0.33.3 (#2466) 2018-09-07 22:08:36 -07:00
Aditya Bist
9ea02bf125 Security: Added user setting for extension policies (#2426)
* added user setting for extension policy

* fix extension action tests
2018-09-07 16:58:37 -07:00
Cory Rivera
2b4de52af4 Remove redundant getChildren method in IModelViewTreeViewDataProvider. (#2463) 2018-09-07 16:37:44 -07:00
Matt Irvine
d3492ebf2f Change some variable names that used reserved keywords (#2457) 2018-09-07 16:25:55 -07:00
Aditya Bist
ff8698f619 Security: Added warning for all vsix extensions (#2406)
* added warning for all vsix extensions

* added sql carbon tag

* added dont show warning for extensions
2018-09-07 16:25:19 -07:00
Anthony Dresser
16bc218ea7 fix formatting on time stamps (#2456) 2018-09-07 16:24:06 -07:00
Anthony Dresser
72d2920dc3 add table options to fix column widths (#2458) 2018-09-07 16:22:40 -07:00
Alan Ren
fb8de0d753 fix select box's screen reader issues (#2462) 2018-09-07 16:17:56 -07:00
Kevin Cunnane
352afc9827 Pixel perfect support for buttons showing correctly in vertical mode (#2460) 2018-09-07 13:40:50 -07:00
Abbie Petchtes
ce699a1c84 change the default lang in editor component to plaintext and fix sample (#2459)
* change the default lang in editor component to plaintext and fix sample

* minor fix
2018-09-07 13:29:34 -07:00
Matt Irvine
cde20d338e Fix extension installation that broke in merge (#2448) 2018-09-07 13:17:32 -07:00
Anthony Dresser
8ab22e9cc8 change layout for gridpanel to correctly handle header size (#2452) 2018-09-07 11:08:27 -07:00
Anthony Dresser
0f2442a7a5 Add fix for flashing during dragging and resize drag box (#2451)
* add fix for flashing during dragging and resize drag box

* remove unnecessary code
2018-09-07 11:08:14 -07:00
Vincent Feng
ba91140ea5 Enable the support for post-connection behaviors for openConnectionDialog (#2455)
* Enable the support for post-connection behaviors for openConnectionDialog.

* Fixed bugs.

* Make everything in IConnectionCompletionOptions optional except saveConnection.

* showConnectionDialogOnError & showFirewallRuleOnError default to true.

* Use types.isUndefinedOrNull to do value checking.

* Minor changes.
2018-09-08 01:08:18 +08:00
Abbie Petchtes
10f05e75ce Add css styles options to all components (#2454)
* add css styling in all components

* formatting

* formatting

* small typo

* small typo

* use builder to add style instead
2018-09-07 09:08:29 -07:00
Kevin Cunnane
287811f4ab Fix bug where webview options weren't revived, causing URI lookup to fail (#2453) 2018-09-06 18:00:23 -07:00
Karl Burtram
a68462c7cb Fix Extension Manager marketplace sorting (#2450) 2018-09-06 17:46:26 -07:00
Vincent Feng
005c28dd3a Accounts: Enable notification for accounts change (#2432)
* Enable notification for accounts change

* Fixed bugs in extHostAccountManagement.test.ts

* Fixed as commented:
1. Removed AccountWithProviderHandle
2. Use a private dictionary _accounts in ExtHostAccountManagement to cache all accounts and corresponding provider handles.
3. getSecurityToken gets provider handle from _accounts for specified account.
4. Added / changed unit tests for getAllAccounts & getSecurityToken
2018-09-07 08:23:28 +08:00
Anthony Dresser
197e1c651f add listeners to make grid the largest (#2447) 2018-09-06 17:00:54 -07:00
Anthony Dresser
c01da0f263 fix off by one in query messages (#2446) 2018-09-06 17:00:41 -07:00
Anthony Dresser
81ff542d0b add copy keybind (#2445) 2018-09-06 17:00:30 -07:00
Karl Burtram
efee27559b Update SQL Ops to 0.33.2 2018-09-06 16:25:59 -07:00
Karl Burtram
dc5408f874 Fix break opening SQL files (#2449) 2018-09-06 15:46:50 -07:00
Chris LaFreniere
7cf9217158 fix for findSubstr not doing URI.file(<filename>).fspath (#2441) 2018-09-06 15:04:16 -07:00
Anthony Dresser
401fc8161a fix dragging (#2438) 2018-09-06 14:43:52 -07:00
Matt Irvine
be2f9a6099 Add "preview features" config switch (#2334)
* Initial working commit for preview features config

* Clean up code

* Update tests

* Remove unused imports

* Update message and options

* Update don't show again message
2018-09-06 14:16:47 -07:00
Karl Burtram
21989aa88e Simplify GitHub templates (#2440) 2018-09-06 14:10:03 -07:00
Karl Burtram
461d041a50 Fix SQLPLAN custom editor support (#2439) 2018-09-06 14:09:34 -07:00
143 changed files with 2530 additions and 667 deletions

View File

@@ -3,17 +3,12 @@ name: Bug report
about: Create a report to help us improve
---
<!-- Please search existing issues to avoid creating duplicates. -->
<!-- Please search existing issues to avoid creating duplicates. -->
<!-- Also please test using the latest insiders build to make sure your issue has not already been fixed. -->
<!-- Use Help > Report Issue to prefill these. -->
- SQL Operations Studio Version:
- OS Version:
Steps to Reproduce:
1.
2.
<!-- Launch with `sqlops --disable-extensions` to check. -->
Does this issue occur when all extensions are disabled?: Yes/No

View File

@@ -1,9 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
<!-- Please search existing issues to avoid creating duplicates. -->
<!-- Describe the feature you'd like. -->

View File

@@ -1,4 +0,0 @@
---
name: Question
---

View File

@@ -1,3 +1,3 @@
disturl "https://atom.io/download/electron"
target "2.0.7"
target "2.0.8"
runtime "electron"

View File

@@ -7,7 +7,7 @@
import * as nls from 'vscode-nls';
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 { Model } from './model';
import { CommandCenter } from './commands';
@@ -98,28 +98,29 @@ export async function activate(context: ExtensionContext): Promise<API> {
throw err;
}
const config = workspace.getConfiguration('git');
const shouldIgnore = config.get<boolean>('ignoreMissingGitWarning') === true;
// {{SQL CARBON EDIT}} turn-off Git missing prompt
//const config = workspace.getConfiguration('git');
//const shouldIgnore = config.get<boolean>('ignoreMissingGitWarning') === true;
if (!shouldIgnore) {
console.warn(err.message);
outputChannel.appendLine(err.message);
outputChannel.show();
// if (!shouldIgnore) {
// console.warn(err.message);
// outputChannel.appendLine(err.message);
// outputChannel.show();
const download = localize('downloadgit', "Download Git");
const neverShowAgain = localize('neverShowAgain', "Don't Show Again");
const choice = await window.showWarningMessage(
localize('notfound', "Git not found. Install it or configure it using the 'git.path' setting."),
download,
neverShowAgain
);
// const download = localize('downloadgit', "Download Git");
// const neverShowAgain = localize('neverShowAgain', "Don't Show Again");
// const choice = await window.showWarningMessage(
// localize('notfound', "Git not found. Install it or configure it using the 'git.path' setting."),
// download,
// neverShowAgain
// );
if (choice === download) {
commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/'));
} else if (choice === neverShowAgain) {
await config.update('ignoreMissingGitWarning', true, true);
}
}
// if (choice === download) {
// commands.executeCommand('vscode.open', Uri.parse('https://git-scm.com/'));
// } else if (choice === neverShowAgain) {
// await config.update('ignoreMissingGitWarning', true, true);
// }
// }
return new NoopAPIImpl();
}

View File

@@ -1,6 +1,6 @@
{
"name": "sqlops",
"version": "0.33.1",
"version": "0.33.5",
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
"author": {
"name": "Microsoft Corporation"
@@ -64,7 +64,7 @@
"reflect-metadata": "^0.1.8",
"rxjs": "5.4.0",
"semver": "^5.5.0",
"slickgrid": "github:anthonydresser/SlickGrid#2.3.25",
"slickgrid": "github:anthonydresser/SlickGrid#2.3.27",
"spdlog": "0.7.1",
"sudo-prompt": "8.2.0",
"svg.js": "^2.2.5",

View File

@@ -3121,6 +3121,19 @@
}
}
},
"gulp-remote-src-vscode": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/gulp-remote-src-vscode/-/gulp-remote-src-vscode-0.5.0.tgz",
"integrity": "sha512-/9vtSk9eI9DEWCqzGieglPqmx0WUQ9pwPHyHFpKmfxqdgqGJC2l0vFMdYs54hLdDsMDEZFLDL2J4ikjc4hQ5HQ==",
"dev": true,
"requires": {
"event-stream": "3.3.4",
"node.extend": "1.1.6",
"request": "2.85.0",
"through2": "2.0.3",
"vinyl": "2.1.0"
}
},
"gulp-sourcemaps": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.4.tgz",
@@ -7423,25 +7436,85 @@
}
},
"vscode": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.14.tgz",
"integrity": "sha512-acfn3fzGtTm7UjChAN7/YjsC0qIyJeuSrJwvm6qb7tLN6Geq1FmCz1JnBOc3kaY+HCLjQBAfwG/CsgnasOdXMw==",
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.21.tgz",
"integrity": "sha512-tJl9eL15ZMm6vzCYYeQ26sSYRuXGMGPsaeIAmG2rOOYRn01jdaDg6I4b9G5Ed6FISdmn6egpKThk4o4om8Ax/A==",
"dev": true,
"requires": {
"glob": "7.1.2",
"gulp-chmod": "2.0.0",
"gulp-filter": "5.1.0",
"gulp-gunzip": "1.0.0",
"gulp-remote-src": "0.4.3",
"gulp-remote-src-vscode": "0.5.0",
"gulp-symdest": "1.1.0",
"gulp-untar": "0.0.6",
"gulp-untar": "0.0.7",
"gulp-vinyl-zip": "2.1.0",
"mocha": "4.1.0",
"request": "2.85.0",
"semver": "5.5.0",
"source-map-support": "0.5.4",
"url-parse": "1.3.0",
"url-parse": "1.4.3",
"vinyl-source-stream": "1.1.2"
},
"dependencies": {
"clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
"dev": true
},
"clone-stats": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
"integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=",
"dev": true
},
"gulp-untar": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/gulp-untar/-/gulp-untar-0.0.7.tgz",
"integrity": "sha512-0QfbCH2a1k2qkTLWPqTX+QO4qNsHn3kC546YhAP3/n0h+nvtyGITDuDrYBMDZeW4WnFijmkOvBWa5HshTic1tw==",
"dev": true,
"requires": {
"event-stream": "3.3.4",
"streamifier": "0.1.1",
"tar": "2.2.1",
"through2": "2.0.3",
"vinyl": "1.2.0"
}
},
"querystringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz",
"integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw==",
"dev": true
},
"replace-ext": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
"integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=",
"dev": true
},
"url-parse": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.3.tgz",
"integrity": "sha512-rh+KuAW36YKo0vClhQzLLveoj8FwPJNu65xLb7Mrt+eZht0IPT0IXgSv8gcMegZ6NvjJUALf6Mf25POlMwD1Fw==",
"dev": true,
"requires": {
"querystringify": "2.0.0",
"requires-port": "1.0.0"
}
},
"vinyl": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
"integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
"dev": true,
"requires": {
"clone": "1.0.4",
"clone-stats": "0.0.1",
"replace-ext": "0.0.1"
}
}
}
},
"vscode-nls": {

View File

@@ -5,7 +5,7 @@
"version": "0.0.1",
"publisher": "demo",
"engines": {
"vscode": "^1.21.0",
"vscode": "^1.26.0",
"sqlops": "*"
},
"categories": [

View File

@@ -128,9 +128,11 @@ export default class MainController implements vscode.Disposable {
}
});
treeView.onDidChangeSelection(selectedNodes => {
selectedNodes.forEach(node => {
console.info('tree node selected: ' + node.label);
});
if (selectedNodes && selectedNodes.selection) {
selectedNodes.selection.forEach(node => {
console.info('tree node selected: ' + node.label);
});
}
});
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
@@ -516,7 +518,8 @@ export default class MainController implements vscode.Disposable {
let runButton = view.modelBuilder.button()
.withProperties({
label: 'Run',
iconPath: runIcon
iconPath: runIcon,
title: 'Run title'
}).component();
let monitorLightPath = vscode.Uri.file(path.join(__dirname, '..', 'media', 'monitor.svg'));
@@ -528,7 +531,8 @@ export default class MainController implements vscode.Disposable {
let monitorButton = view.modelBuilder.button()
.withProperties({
label: 'Monitor',
iconPath: monitorIcon
iconPath: monitorIcon,
title: 'Monitor title'
}).component();
let toolbarModel = view.modelBuilder.toolbarContainer()
.withToolbarItems([{

View File

@@ -2865,6 +2865,10 @@ qs@~6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
querystringify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.0.0.tgz#fa3ed6e68eb15159457c89b37bc6472833195755"
querystringify@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb"
@@ -3131,7 +3135,7 @@ require-main-filename@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
requires-port@~1.0.0:
requires-port@^1.0.0, requires-port@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
@@ -3755,6 +3759,13 @@ url-parse@^1.1.9:
querystringify "~1.0.0"
requires-port "~1.0.0"
url-parse@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.3.tgz#bfaee455c889023219d757e045fa6a684ec36c15"
dependencies:
querystringify "^2.0.0"
requires-port "^1.0.0"
use@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/use/-/use-3.1.0.tgz#14716bf03fdfefd03040aef58d8b4b85f3a7c544"
@@ -3933,9 +3944,9 @@ vscode-nls@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.2.tgz#3817eca5b985c2393de325197cf4e15eb2aa5350"
vscode@^1.1.14:
version "1.1.18"
resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.18.tgz#e9227265dc72fc826bd6cd7bd21193f4e48fa671"
vscode@^1.1.18:
version "1.1.21"
resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.21.tgz#1c8253d6238aefb4112d6e58cf975ad25313dafc"
dependencies:
glob "^7.1.2"
gulp-chmod "^2.0.0"
@@ -3949,7 +3960,7 @@ vscode@^1.1.14:
request "^2.83.0"
semver "^5.4.1"
source-map-support "^0.5.0"
url-parse "^1.1.9"
url-parse "^1.4.3"
vinyl-source-stream "^1.1.0"
vso-node-api@^6.1.2-preview:

View File

@@ -10,7 +10,7 @@ export const IBreadcrumbService = new InjectionToken<IBreadcrumbService>('breadc
export interface IBreadcrumbService {
breadcrumbItem: Subject<MenuItem[]>;
setBreadcrumbs(any): void;
setBreadcrumbs(page: any): void;
}
export interface MenuItem {

View File

@@ -23,6 +23,18 @@ export class Button extends vsButton {
this.$el.style('outline-color', this.buttonFocusOutline ? this.buttonFocusOutline.toString() : null);
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 {

View File

@@ -217,7 +217,7 @@ export abstract class Modal extends Disposable implements IThemable {
if (this._modalOptions.isAngular === false && this._modalOptions.hasErrors) {
let builder = errorMessagesInFooter ? this._leftFooter : body;
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.style.visibility = 'hidden';
});

View File

@@ -180,14 +180,16 @@ export class TabbedPanel extends Disposable implements IThemable {
}
public layout(dimension: Dimension): void {
this._currentDimensions = dimension;
this.$parent.style('height', dimension.height + 'px');
this.$parent.style('width', dimension.width + 'px');
this.$header.style('width', dimension.width + 'px');
this.$body.style('width', dimension.width + 'px');
const bodyHeight = dimension.height - (this._headerVisible ? this.headersize : 0);
this.$body.style('height', bodyHeight + 'px');
this._layoutCurrentTab(new Dimension(dimension.width, bodyHeight));
if (dimension) {
this._currentDimensions = dimension;
this.$parent.style('height', dimension.height + 'px');
this.$parent.style('width', dimension.width + 'px');
this.$header.style('width', dimension.width + 'px');
this.$body.style('width', dimension.width + 'px');
const bodyHeight = dimension.height - (this._headerVisible ? this.headersize : 0);
this.$body.style('height', bodyHeight + 'px');
this._layoutCurrentTab(new Dimension(dimension.width, bodyHeight));
}
}
private _layoutCurrentTab(dimension: Dimension): void {

View File

@@ -109,6 +109,9 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
private _onDidSashReset = new Emitter<void>();
readonly onDidSashReset = this._onDidSashReset.event;
private _onScroll = new Emitter<number>();
readonly onScroll = this._onScroll.event;
get length(): number {
return this.viewItems.length;
}
@@ -124,6 +127,7 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
debounceEvent(this.scrollable.onScroll, (l, e) => e, 25)(e => {
this.render(e.scrollTop, e.height);
this.relayout();
this._onScroll.fire(e.scrollTop);
});
let domNode = this.scrollable.getDomNode();
dom.addClass(this.el, 'monaco-scroll-split-view');
@@ -330,9 +334,16 @@ export class ScrollableSplitView extends HeightMap implements IDisposable {
this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndex);
}
public setScrollPosition(position: number) {
this.scrollable.setScrollPosition({ scrollTop: position });
}
layout(size: number): void {
const previousSize = Math.max(this.size, this.contentSize);
const previousSize = this.size;
this.size = size;
this.contentSize = 0;
this.lastRenderHeight = undefined;
this.lastRenderTop = undefined;
this.resize(this.viewItems.length - 1, size - previousSize);
}

View File

@@ -69,6 +69,9 @@ export class SelectBox extends vsSelectBox {
if (container) {
this.element = dom.append(container, $('.monaco-selectbox.idle'));
}
// explicitly set the accessible role so that the screen readers can read the control type properly
this.selectElement.setAttribute('role', 'combobox');
}
public style(styles: ISelectBoxStyles): void {

View File

@@ -7,6 +7,7 @@
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
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
@@ -50,6 +51,14 @@ export class AdditionalKeyBindings<T> implements Slick.Plugin<T> {
}
} else if (event.equals(KeyCode.End | KeyMod.CtrlCmd)) {
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 {
handled = false;
}

View File

@@ -0,0 +1,145 @@
import { mixin } from 'vs/base/common/objects';
const defaultOptions: ICellRangeSelectorOptions = {
selectionCss: {
'border': '2px dashed blue'
},
offset: {
top: -1,
left: -1,
height: 2,
width: 2
},
dragClass: 'drag'
};
export interface ICellRangeSelectorOptions {
selectionCss?: { [key: string]: string };
cellDecorator?: ICellRangeDecorator;
offset?: { top: number, left: number, height: number, width: number };
dragClass?: string;
}
export interface ICellRangeSelector<T> extends Slick.Plugin<T> {
onCellRangeSelected: Slick.Event<{ range: Slick.Range }>;
onBeforeCellRangeSelected: Slick.Event<Slick.Cell>;
}
export interface ICellRangeDecorator {
show(range: Slick.Range);
hide();
}
export class CellRangeSelector<T> implements ICellRangeSelector<T> {
private grid: Slick.Grid<T>;
private dragging: boolean;
private handler = new Slick.EventHandler();
private decorator: ICellRangeDecorator;
private canvas: HTMLCanvasElement;
private currentlySelectedRange: { start: Slick.Cell, end: Slick.Cell };
public onBeforeCellRangeSelected = new Slick.Event<Slick.Cell>();
public onCellRangeSelected = new Slick.Event<{ range: Slick.Range }>();
constructor(private options: ICellRangeSelectorOptions) {
require.__$__nodeRequire('slickgrid/plugins/slick.cellrangedecorator');
this.options = mixin(this.options, defaultOptions, false);
}
public init(grid: Slick.Grid<T>) {
this.decorator = this.options.cellDecorator || new (<any>Slick).CellRangeDecorator(grid, this.options);
this.grid = grid;
this.canvas = this.grid.getCanvasNode();
this.handler
.subscribe(this.grid.onDragInit, e => this.handleDragInit(e))
.subscribe(this.grid.onDragStart, (e, dd) => this.handleDragStart(e, dd))
.subscribe(this.grid.onDrag, (e, dd) => this.handleDrag(e, dd))
.subscribe(this.grid.onDragEnd, (e, dd) => this.handleDragEnd(e, dd));
}
public destroy() {
this.handler.unsubscribeAll();
}
public getCellDecorator() {
return this.decorator;
}
public getCurrentRange() {
return this.currentlySelectedRange;
}
private handleDragInit(e: DOMEvent) {
// prevent the grid from cancelling drag'n'drop by default
e.stopImmediatePropagation();
}
private handleDragStart(e: MouseEvent, dd: Slick.OnDragStartEventArgs<T>) {
let cell = this.grid.getCellFromEvent(e);
if (this.onBeforeCellRangeSelected.notify(cell) !== false) {
if (this.grid.canCellBeSelected(cell.row, cell.cell)) {
this.dragging = true;
e.stopImmediatePropagation();
}
}
if (!this.dragging) {
return;
}
this.canvas.classList.add(this.options.dragClass);
this.grid.setActiveCell(cell.row, cell.cell);
let start = this.grid.getCellFromPoint(
dd.startX - $(this.canvas).offset().left,
dd.startY - $(this.canvas).offset().top);
dd.range = { start: start, end: undefined };
this.currentlySelectedRange = dd.range;
return this.decorator.show(new Slick.Range(start.row, start.cell));
}
private handleDrag(e: MouseEvent, dd: Slick.OnDragEventArgs<T>) {
if (!this.dragging) {
return;
}
e.stopImmediatePropagation();
let end = this.grid.getCellFromPoint(
e.pageX - $(this.canvas).offset().left,
e.pageY - $(this.canvas).offset().top);
if (!this.grid.canCellBeSelected(end.row, end.cell)) {
return;
}
dd.range.end = end;
this.currentlySelectedRange = dd.range;
this.decorator.show(new Slick.Range(dd.range.start.row, dd.range.start.cell, end.row, end.cell));
}
private handleDragEnd(e: MouseEvent, dd: Slick.OnDragEndEventArgs<T>) {
if (!this.dragging) {
return;
}
this.canvas.classList.remove(this.options.dragClass);
this.dragging = false;
e.stopImmediatePropagation();
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({
range: new Slick.Range(
dd.range.start.row,
dd.range.start.cell,
dd.range.end.row,
dd.range.end.cell
)
});
}
}

View File

@@ -3,15 +3,8 @@
import { mixin } from 'vs/base/common/objects';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { IThemeService } from 'vs/platform/theme/common/themeService';
require.__$__nodeRequire('slickgrid/plugins/slick.cellrangedecorator');
require.__$__nodeRequire('slickgrid/plugins/slick.cellrangeselector');
export interface ICellRangeSelector<T> extends Slick.Plugin<T> {
onCellRangeSelected: Slick.Event<{ range: Slick.Range }>;
onBeforeCellRangeSelected: Slick.Event<Slick.Cell>;
}
import { CellRangeSelector, ICellRangeSelector } from 'sql/base/browser/ui/table/plugins/cellRangeSelector';
export interface ICellSelectionModelOptions {
cellRangeSelector?: any;
@@ -36,7 +29,7 @@ export class CellSelectionModel<T> implements Slick.SelectionModel<T, Array<Slic
this.selector = this.options.cellRangeSelector;
} else {
// this is added by the noderequires above
this.selector = new (<any>Slick).CellRangeSelector({ selectionCss: { 'border': '2px dashed grey' } });
this.selector = new CellRangeSelector({ selectionCss: { 'border': '2px dashed grey' } });
}
}

View File

@@ -0,0 +1,62 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { Emitter, Event } from 'vs/base/common/event';
import { isUndefinedOrNull } from 'vs/base/common/types';
/**
* Implements the various additional navigation keybindings we want out of slickgrid
*/
export class CopyKeybind<T> implements Slick.Plugin<T> {
private grid: Slick.Grid<T>;
private handler = new Slick.EventHandler();
private _onCopy = new Emitter<Slick.Range[]>();
public onCopy: Event<Slick.Range[]> = this._onCopy.event;
public init(grid: Slick.Grid<T>) {
this.grid = grid;
this.handler.subscribe(this.grid.onKeyDown, (e, args) => this.handleKeyDown(e, args));
}
public destroy() {
this.handler.unsubscribeAll();
}
private handleKeyDown(e: KeyboardEvent, args: Slick.OnKeyDownEventArgs<T>): void {
let event = new StandardKeyboardEvent(e);
let handled = false;
if (event.equals(KeyCode.KEY_C | KeyMod.CtrlCmd)) {
handled = true;
let selectionModel = this.grid.getSelectionModel();
let ranges: Slick.Range[];
// check to see if we can get the range from the model directly
if (selectionModel) {
ranges = selectionModel.getSelectedRanges();
} else {
let selectedRows = this.grid.getSelectedRows();
let startColumn = 0;
// check for number column
if (!isUndefinedOrNull(this.grid.getColumns()[0].selectable) && !this.grid.getColumns()[0].selectable) {
startColumn = 1;
}
ranges = [new Slick.Range(selectedRows[0], startColumn, selectedRows[selectedRows.length - 1], this.grid.getColumns().length)]
}
this._onCopy.fire(ranges);
}
if (handled) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
}
}
}

View File

@@ -36,23 +36,31 @@ export class RowNumberColumn<T> implements Slick.Plugin<T> {
private handleClick(e: MouseEvent, args: Slick.OnClickEventArgs<T>): void {
if (this.grid.getColumns()[args.cell].id === 'rowNumber') {
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 {
if (args.column.id === 'rowNumber') {
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> {
// 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 {
id: 'rowNumber',
name: '',
field: 'rowNumber',
width: this.options.numberOfRows.toString().length * sizePerDigit,
width: columnWidth,
minWidth: columnWidth,
maxWidth: columnWidth,
resizable: false,
cssClass: this.options.cssClass,
focusable: false,

View File

@@ -166,6 +166,10 @@ export class Table<T extends Slick.SlickData> extends Widget implements IThemabl
this._grid.setData(this._data, true);
}
getData(): Slick.DataProvider<T> {
return this._data;
}
get columns(): Slick.Column<T>[] {
return this._grid.getColumns();
}
@@ -244,7 +248,6 @@ export class Table<T extends Slick.SlickData> extends Widget implements IThemabl
}
}
this.resizeCanvas();
this.autosizeColumns();
}
autosizeColumns() {
@@ -308,10 +311,15 @@ export class Table<T extends Slick.SlickData> extends Widget implements IThemabl
if (styles.listHoverBackground) {
content.push(`.monaco-table.${this.idPrefix} .slick-row:hover { background-color: ${styles.listHoverBackground}; }`);
// handle no coloring during drag
content.push(`.monaco-table.${this.idPrefix} .drag .slick-row:hover { background-color: inherit; }`);
}
if (styles.listHoverForeground) {
content.push(`.monaco-table.${this.idPrefix} .slick-row:hover { color: ${styles.listHoverForeground}; }`);
// handle no coloring during drag
content.push(`.monaco-table.${this.idPrefix} .drag .slick-row:hover { color: inherit; }`);
}
if (styles.listSelectionOutline) {

View File

@@ -5,6 +5,7 @@
'use strict';
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
@@ -37,3 +38,52 @@ export function echo<T>(event: Event<T>, nextTick = false, buffer: T[] = []): {
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
};
}

View File

@@ -63,21 +63,21 @@
background: url("globalerror.svg") center center no-repeat;
}
.vs .icon.error,
.vs-dark .icon.error,
.hc-black .icon.error {
.vs .sql.icon.error,
.vs-dark .sql.icon.error,
.hc-black .sql.icon.error {
content: url("status_error.svg");
}
.vs .icon.warning,
.vs-dark .icon.warning,
.hc-black .icon.warning {
.vs .sql.icon.warning,
.vs-dark .sql.icon.warning,
.hc-black .sql.icon.warning {
content: url("status_warning.svg");
}
.vs .icon.info,
.vs-dark .icon.info,
.hc-black .icon.info {
.vs .sql.icon.info,
.vs-dark .sql.icon.info,
.hc-black .sql.icon.info {
content: url("status_info.svg");
}

View File

@@ -117,7 +117,7 @@ export class AccountPicker extends Disposable {
// Create refresh account action
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 });
this._refreshAccountAction = this._instantiationService.createInstance(RefreshAccountAction);
actionBar.push(this._refreshAccountAction, { icon: false, label: true });

View File

@@ -123,6 +123,7 @@ export class ConnectionStore {
.then(savedCred => {
if (savedCred) {
credentialsItem.password = savedCred.password;
credentialsItem.options['password'] = savedCred.password;
}
resolve({ profile: credentialsItem, savedCred: !!savedCred });
},

View File

@@ -100,10 +100,10 @@ export class ConnectionDialogWidget extends Modal {
public refresh(): void {
let filteredProviderTypes = this.providerTypeOptions;
if (this._newConnectionParams && this._newConnectionParams.providers) {
if (this._newConnectionParams && this._newConnectionParams.providers) {
let validProviderNames = Object.keys(this.providerNameToDisplayNameMap).filter(x => this.includeProvider(x, this._newConnectionParams));
if (validProviderNames && validProviderNames.length > 0) {
filteredProviderTypes = filteredProviderTypes.filter(x => validProviderNames.find( v => this.providerNameToDisplayNameMap[v] === x) !== undefined);
filteredProviderTypes = filteredProviderTypes.filter(x => validProviderNames.find(v => this.providerNameToDisplayNameMap[v] === x) !== undefined);
}
}
this._providerTypeSelectBox.setOptions(filteredProviderTypes);
@@ -118,8 +118,8 @@ export class ConnectionDialogWidget extends Modal {
container.appendChild(connectionContainer.getHTMLElement());
this._bodyBuilder = new Builder(connectionContainer.getHTMLElement());
this._providerTypeSelectBox = new SelectBox(this.providerTypeOptions, this.selectedProviderType, this._contextViewService);
const connectTypeLabel = localize('connectType', 'Connection type');
this._providerTypeSelectBox = new SelectBox(this.providerTypeOptions, this.selectedProviderType, this._contextViewService, undefined, { ariaLabel: connectTypeLabel });
// Recent connection tab
let recentConnectionTab = $('.connection-recent-tab');
recentConnectionTab.div({ class: 'connection-recent', id: 'recentConnection' }, (builder) => {
@@ -182,7 +182,6 @@ export class ConnectionDialogWidget extends Modal {
});
this._bodyBuilder.div({ class: 'connection-type' }, (modelTableContent) => {
let connectTypeLabel = localize('connectType', 'Connection type');
modelTableContent.element('table', { class: 'connection-table-content' }, (tableContainer) => {
DialogHelper.appendInputSelectBox(
DialogHelper.appendRow(tableContainer, connectTypeLabel, 'connection-label', 'connection-input'), this._providerTypeSelectBox);
@@ -450,4 +449,4 @@ export class ConnectionDialogWidget extends Modal {
public get databaseDropdownExpanded(): boolean {
return this._databaseDropdownExpanded;
}
}
}

View File

@@ -65,6 +65,7 @@ export class ConnectionWidget {
private _databaseDropdownExpanded: boolean = false;
private _defaultDatabaseName: string = localize('defaultDatabaseOption', '<Default>');
private _loadingDatabaseName: string = localize('loadingDatabaseOption', 'Loading...');
private _serverGroupDisplayString: string = localize('serverGroup', 'Server group');
public DefaultServerGroup: IConnectionProfileGroup = {
id: '',
name: localize('defaultServerGroup', '<Default>'),
@@ -112,14 +113,14 @@ export class ConnectionWidget {
} else {
authTypeOption.defaultValue = this.getAuthTypeDisplayName(Constants.sqlLogin);
}
this._authTypeSelectBox = new SelectBox(authTypeOption.categoryValues.map(c => c.displayName), authTypeOption.defaultValue, this._contextViewService);
this._authTypeSelectBox = new SelectBox(authTypeOption.categoryValues.map(c => c.displayName), authTypeOption.defaultValue, this._contextViewService, undefined, { ariaLabel: authTypeOption.displayName });
}
this._providerName = providerName;
}
public createConnectionWidget(container: HTMLElement): void {
this._serverGroupOptions = [this.DefaultServerGroup];
this._serverGroupSelectBox = new SelectBox(this._serverGroupOptions.map(g => g.name), this.DefaultServerGroup.name, this._contextViewService);
this._serverGroupSelectBox = new SelectBox(this._serverGroupOptions.map(g => g.name), this.DefaultServerGroup.name, this._contextViewService, undefined, { ariaLabel: this._serverGroupDisplayString });
this._previousGroupOption = this._serverGroupSelectBox.value;
this._builder = $().div({ class: 'connection-table' }, (modelTableContent) => {
modelTableContent.element('table', { class: 'connection-table-content' }, (tableContainer) => {
@@ -155,11 +156,6 @@ export class ConnectionWidget {
}
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
let serverNameOption = this._optionsMaps[ConnectionOptionSpecialType.serverName];
let serverNameBuilder = DialogHelper.appendRow(this._tableContainer, serverNameOption.displayName, 'connection-label', 'connection-input');
@@ -193,7 +189,6 @@ export class ConnectionWidget {
},
ariaLabel: userNameOption.displayName
});
// Password
let passwordOption = this._optionsMaps[ConnectionOptionSpecialType.password];
let passwordBuilder = DialogHelper.appendRow(this._tableContainer, passwordOption.displayName, 'connection-label', 'connection-input');
@@ -219,10 +214,14 @@ export class ConnectionWidget {
});
// Server group
let serverGroupLabel = localize('serverGroup', 'Server group');
let serverGroupBuilder = DialogHelper.appendRow(this._tableContainer, serverGroupLabel, 'connection-label', 'connection-input');
let serverGroupBuilder = DialogHelper.appendRow(this._tableContainer, this._serverGroupDisplayString, 'connection-label', 'connection-input');
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...');
this._advancedButton = this.createAdvancedButton(this._tableContainer, AdvancedLabel);
}
@@ -399,7 +398,7 @@ export class ConnectionWidget {
public focusOnOpen(): void {
this._handleClipboard();
this._connectionNameInputBox.focus();
this._serverNameInputBox.focus();
this.focusPasswordIfNeeded();
this.clearValidationMessages();
}
@@ -493,6 +492,7 @@ export class ConnectionWidget {
this._databaseNameInputBox.enabled = false;
this._userNameInputBox.disable();
this._passwordInputBox.disable();
this._connectionNameInputBox.disable();
this._rememberPasswordCheckBox.enabled = false;
if (this._authTypeSelectBox) {
this._authTypeSelectBox.disable();
@@ -504,6 +504,7 @@ export class ConnectionWidget {
this._serverGroupSelectBox.enable();
this._serverNameInputBox.enable();
this._connectionNameInputBox.enable();
this._databaseNameInputBox.enabled = true;
let currentAuthType: AuthenticationType = undefined;
if (this._authTypeSelectBox) {

View File

@@ -31,7 +31,7 @@ import * as nls from 'vs/nls';
import * as objects from 'vs/base/common/objects';
import { Event, Emitter } from 'vs/base/common/event';
import { Action } from 'vs/base/common/actions';
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import Severity from 'vs/base/common/severity';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -96,7 +96,8 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig
@Inject(forwardRef(() => ChangeDetectorRef)) protected _cd: ChangeDetectorRef,
@Inject(IInstantiationService) private instantiationService: IInstantiationService,
@Inject(INotificationService) private notificationService: INotificationService,
@Inject(IAngularEventingService) private angularEventingService: IAngularEventingService
@Inject(IAngularEventingService) private angularEventingService: IAngularEventingService,
@Inject(IConfigurationService) private configurationService: IConfigurationService
) {
super();
}
@@ -138,6 +139,12 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig
// Before separating tabs into pinned / shown, ensure that the home tab is always set up as expected
allTabs = this.setAndRemoveHomeTab(allTabs, homeWidgets);
// If preview features are disabled only show the home tab
let extensionTabsEnabled = this.configurationService.getValue('workbench')['enablePreviewFeatures'];
if (!extensionTabsEnabled) {
allTabs = [];
}
// Load tab setting configs
this._tabSettingConfigs = this.dashboardService.getSettings<Array<TabSettingConfig>>([this.context, 'tabs'].join('.'));
@@ -164,9 +171,13 @@ export abstract class DashboardPage extends AngularDisposable implements IConfig
// Set panel actions
let openedTabs = [...pinnedDashboardTabs, ...alwaysShowTabs];
let addNewTabAction = this.instantiationService.createInstance(AddFeatureTabAction, allTabs, openedTabs, this.dashboardService.getUnderlyingUri());
this._tabsDispose.push(addNewTabAction);
this.panelActions = [addNewTabAction];
if (extensionTabsEnabled) {
let addNewTabAction = this.instantiationService.createInstance(AddFeatureTabAction, allTabs, openedTabs, this.dashboardService.getUnderlyingUri());
this._tabsDispose.push(addNewTabAction);
this.panelActions = [addNewTabAction];
} else {
this.panelActions = [];
}
this._cd.detectChanges();
this._tabsDispose.push(this.dashboardService.onPinUnpinTab(e => {

View File

@@ -18,6 +18,7 @@ import * as nls from 'vs/nls';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export class DatabaseDashboardPage extends DashboardPage implements OnInit {
protected propertiesWidget: WidgetConfig = {
@@ -43,9 +44,10 @@ export class DatabaseDashboardPage extends DashboardPage implements OnInit {
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
@Inject(IInstantiationService) instantiationService: IInstantiationService,
@Inject(INotificationService) notificationService: INotificationService,
@Inject(IAngularEventingService) angularEventingService: IAngularEventingService
@Inject(IAngularEventingService) angularEventingService: IAngularEventingService,
@Inject(IConfigurationService) configurationService: IConfigurationService
) {
super(dashboardService, el, _cd, instantiationService, notificationService, angularEventingService);
super(dashboardService, el, _cd, instantiationService, notificationService, angularEventingService, configurationService);
this._register(dashboardService.onUpdatePage(() => {
this.refresh(true);
this._cd.detectChanges();

View File

@@ -18,6 +18,7 @@ import * as nls from 'vs/nls';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export class ServerDashboardPage extends DashboardPage implements OnInit {
protected propertiesWidget: WidgetConfig = {
@@ -44,9 +45,10 @@ export class ServerDashboardPage extends DashboardPage implements OnInit {
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
@Inject(IInstantiationService) instantiationService: IInstantiationService,
@Inject(INotificationService) notificationService: INotificationService,
@Inject(IAngularEventingService) angularEventingService: IAngularEventingService
@Inject(IAngularEventingService) angularEventingService: IAngularEventingService,
@Inject(IConfigurationService) configurationService: IConfigurationService
) {
super(dashboardService, el, _cd, instantiationService, notificationService, angularEventingService);
super(dashboardService, el, _cd, instantiationService, notificationService, angularEventingService, configurationService);
// revert back to default database
this._letDashboardPromise = this.dashboardService.connectionManagementService.changeDatabase('master');
}

View File

@@ -10,6 +10,7 @@ import * as TelemetryUtils from 'sql/common/telemetryUtilities';
import { IInsightsView, IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
import { memoize, unmemoize } from 'sql/base/common/decorators';
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 { Color } from 'vs/base/common/color';
@@ -21,29 +22,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
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 {
if (types.isObject(source)) {
mixin(destination, source, overwrite, customMixin);

View File

@@ -0,0 +1,32 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
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'
}

View File

@@ -3,8 +3,9 @@
* 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 { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
import * as colors from 'vs/platform/theme/common/colorRegistry';

View File

@@ -3,8 +3,8 @@
* 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 { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
export default class DoughnutChart extends PieChart {
protected readonly chartType: ChartType = ChartType.Doughnut;

View File

@@ -3,8 +3,8 @@
* 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 { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
export default class HorizontalBarChart extends BarChart {
protected readonly chartType: ChartType = ChartType.HorizontalBar;

View File

@@ -3,16 +3,13 @@
* 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 { memoize, unmemoize } from 'sql/base/common/decorators';
import { mixin } from 'vs/base/common/objects';
import { clone } from 'sql/base/common/objects';
export enum DataType {
Number = 'number',
Point = 'point'
}
import { ChartType, DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
export interface ILineConfig extends IBarChartConfig {
dataType?: DataType;

View File

@@ -3,7 +3,8 @@
* 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 {
protected readonly chartType: ChartType = ChartType.Pie;

View File

@@ -3,11 +3,12 @@
* 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 { 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 { clone } from 'sql/base/common/objects';
const defaultScatterConfig = mixin(clone(defaultChartConfig), { dataType: 'point', dataDirection: 'horizontal' }) as ILineConfig;

View File

@@ -3,9 +3,10 @@
* 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 { 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 { Color } from 'vs/base/common/color';

View File

@@ -86,7 +86,7 @@ export class TasksWidget extends DashboardWidget implements IDashboardWidget, On
}).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() {

View File

@@ -65,7 +65,7 @@
<div class="option check" #encryptCheckContainer>
</div>
<div class="option" #encryptWarningContainer>
<div class="icon warning">
<div class="sql icon warning">
</div>
<div class="warning-message">
{{localizedStrings.NO_ENCRYPTOR_WARNING}}

View File

@@ -221,7 +221,7 @@ export class BackupComponent {
ariaLabel: LocalizedStrings.RECOVERY_MODEL
});
// Set backup type
this.backupTypeSelectBox = new SelectBox([], '', this.contextViewService);
this.backupTypeSelectBox = new SelectBox([], '', this.contextViewService, undefined, { ariaLabel: this.localizedStrings.BACKUP_TYPE });
this.backupTypeSelectBox.render(this.backupTypeElement.nativeElement);
// Set copy-only check box
@@ -283,13 +283,13 @@ export class BackupComponent {
this.removePathButton.title = localize('removeFile', 'Remove files');
// Set compression
this.compressionSelectBox = new SelectBox(this.compressionOptions, this.compressionOptions[0], this.contextViewService);
this.compressionSelectBox = new SelectBox(this.compressionOptions, this.compressionOptions[0], this.contextViewService, undefined, { ariaLabel: this.localizedStrings.SET_BACKUP_COMPRESSION });
this.compressionSelectBox.render(this.compressionElement.nativeElement);
// Set encryption
this.algorithmSelectBox = new SelectBox(this.encryptionAlgorithms, this.encryptionAlgorithms[0], this.contextViewService);
this.algorithmSelectBox = new SelectBox(this.encryptionAlgorithms, this.encryptionAlgorithms[0], this.contextViewService, undefined, { ariaLabel: this.localizedStrings.ALGORITHM });
this.algorithmSelectBox.render(this.encryptionAlgorithmElement.nativeElement);
this.encryptorSelectBox = new SelectBox([], '', this.contextViewService);
this.encryptorSelectBox = new SelectBox([], '', this.contextViewService, undefined, { ariaLabel: this.localizedStrings.CERTIFICATE_OR_ASYMMETRIC_KEY });
this.encryptorSelectBox.render(this.encryptorElement.nativeElement);
// Set media
@@ -911,4 +911,4 @@ export class BackupComponent {
return backupInfo;
}
}
}

View File

@@ -273,7 +273,7 @@ export class RestoreDialog extends Modal {
labelContainer.hide();
this._restorePlanData = new TableDataView<Slick.SlickData>();
this._restorePlanTable = new Table<Slick.SlickData>(labelContainer.getHTMLElement(),
{ dataProvider: this._restorePlanData, columns: this._restorePlanColumn }, { enableColumnReorder: false });
{ dataProvider: this._restorePlanData, columns: this._restorePlanColumn }, { enableColumnReorder: false });
this._restorePlanTable.setSelectionModel(new RowSelectionModel({ selectActiveRow: false }));
this._restorePlanTable.onSelectedRowsChanged((e, data) => this.backupFileCheckboxChanged(e, data));
});
@@ -330,7 +330,7 @@ export class RestoreDialog extends Modal {
}];
this._fileListData = new TableDataView<FileListElement>();
this._fileListTable = new Table<FileListElement>(fileNameContainer.getHTMLElement(),
{ dataProvider : this._fileListData, columns } , { enableColumnReorder: false });
{ dataProvider: this._fileListData, columns }, { enableColumnReorder: false });
this._fileListTable.setSelectionModel(new RowSelectionModel());
});
});
@@ -541,7 +541,7 @@ export class RestoreDialog extends Modal {
});
inputContainer.div({ class: 'dialog-input' }, (inputCellContainer) => {
selectBox = new SelectBox(options, selectedOption, this._contextViewService, inputCellContainer.getHTMLElement());
selectBox = new SelectBox(options, selectedOption, this._contextViewService, inputCellContainer.getHTMLElement(), { ariaLabel: label });
selectBox.render(inputCellContainer.getHTMLElement());
});
});

View File

@@ -25,7 +25,7 @@ classes should alter those!
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
height: 16px;
height: 28px;
line-height: 16px;
margin: 0;
padding: 4px;
@@ -35,7 +35,7 @@ classes should alter those!
border-bottom: 2px solid #bbb;
float: left;
background-color: #eee;
box-sizing: content-box;
box-sizing: border-box;
}
.slick-headerrow-column.ui-state-default, .slick-footerrow-column.ui-state-default {

View File

@@ -88,7 +88,7 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
@Inject(forwardRef(() => ChangeDetectorRef)) cd: ChangeDetectorRef,
@Inject(IBootstrapParams) params: IEditDataComponentParams,
@Inject(IInstantiationService) private instantiationService: IInstantiationService,
@Inject(INotificationService) private notificationService: INotificationService,
@Inject(INotificationService) notificationService: INotificationService,
@Inject(IContextMenuService) contextMenuService: IContextMenuService,
@Inject(IKeybindingService) keybindingService: IKeybindingService,
@Inject(IContextKeyService) contextKeyService: IContextKeyService,
@@ -96,7 +96,7 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
@Inject(IClipboardService) clipboardService: IClipboardService,
@Inject(IQueryEditorService) queryEditorService: IQueryEditorService
) {
super(el, cd, contextMenuService, keybindingService, contextKeyService, configurationService, clipboardService, queryEditorService);
super(el, cd, contextMenuService, keybindingService, contextKeyService, configurationService, clipboardService, queryEditorService, notificationService);
this._el.nativeElement.className = 'slickgridContainer';
this.dataService = params.dataService;
this.actionProvider = this.instantiationService.createInstance(EditDataGridActionProvider, this.dataService, this.onGridSelectAll(), this.onDeleteRow(), this.onRevertRow());

View File

@@ -37,6 +37,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { INotificationService } from 'vs/platform/notification/common/notification';
export abstract class GridParentComponent {
// CONSTANTS
@@ -100,7 +101,8 @@ export abstract class GridParentComponent {
protected contextKeyService: IContextKeyService,
protected configurationService: IConfigurationService,
protected clipboardService: IClipboardService,
protected queryEditorService: IQueryEditorService
protected queryEditorService: IQueryEditorService,
protected notificationService: INotificationService
) {
this.toDispose = [];
}

View File

@@ -16,7 +16,7 @@ import { IGridDataSet } from 'sql/parts/grid/common/interfaces';
import { IInsightData, IInsightsView, IInsightsConfig } from 'sql/parts/dashboard/widgets/insights/interfaces';
import { Extensions, IInsightRegistry } from 'sql/platform/dashboard/common/insightRegistry';
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 { IChartViewActionContext, CopyAction, CreateInsightAction, SaveImageAction } from 'sql/parts/grid/views/query/chartViewerActions';
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 { IQueryModelService } from 'sql/parts/query/execution/queryModel';
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
import { LegendPosition, DataDirection, DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
/* Insights */
import {
ChartInsight, DataDirection, LegendPosition
ChartInsight
} from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
import { IDisposable } from 'vs/base/common/lifecycle';

View File

@@ -42,6 +42,8 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { localize } from 'vs/nls';
export const QUERY_SELECTOR: string = 'query-component';
@@ -126,7 +128,9 @@ export class QueryComponent extends GridParentComponent implements OnInit, OnDes
}
},
{
showCondition: () => { return true; },
showCondition: () => {
return this.configurationService.getValue('workbench')['enablePreviewFeatures'];
},
icon: () => { return 'viewChart'; },
hoverText: () => { return LocalizedConstants.viewChartLabel; },
functionality: (batchId, resultId, index) => {
@@ -187,9 +191,10 @@ export class QueryComponent extends GridParentComponent implements OnInit, OnDes
@Inject(IContextKeyService) contextKeyService: IContextKeyService,
@Inject(IConfigurationService) configurationService: IConfigurationService,
@Inject(IClipboardService) clipboardService: IClipboardService,
@Inject(IQueryEditorService) queryEditorService: IQueryEditorService
@Inject(IQueryEditorService) queryEditorService: IQueryEditorService,
@Inject(INotificationService) notificationService: INotificationService,
) {
super(el, cd, contextMenuService, keybindingService, contextKeyService, configurationService, clipboardService, queryEditorService);
super(el, cd, contextMenuService, keybindingService, contextKeyService, configurationService, clipboardService, queryEditorService, notificationService);
this._el.nativeElement.className = 'slickgridContainer';
this.rowHeight = configurationService.getValue<any>('resultsGrid').rowHeight;
configurationService.onDidChangeConfiguration(e => {

View File

@@ -13,11 +13,11 @@ import * as sqlops from 'sqlops';
import { ComponentWithIconBase } from 'sql/parts/modelComponents/componentWithIconBase';
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
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 { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
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';
@@ -42,9 +42,10 @@ export default class ButtonComponent extends ComponentWithIconBase implements IC
@ViewChild('fileInput', { read: ElementRef }) private _fileInputContainer: ElementRef;
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
@Inject(forwardRef(() => ElementRef)) el: ElementRef
) {
super(changeRef);
super(changeRef, el);
}
ngOnInit(): void {
@@ -63,7 +64,7 @@ export default class ButtonComponent extends ComponentWithIconBase implements IC
if (this._fileInputContainer) {
const self = this;
this._fileInputContainer.nativeElement.onchange = () => {
let file = self._fileInputContainer.nativeElement.files[0];
let file = self._fileInputContainer.nativeElement.files[0];
let reader = new FileReader();
reader.onload = (e) => {
let text = (<FileReader>e.target).result;
@@ -100,6 +101,7 @@ export default class ButtonComponent extends ComponentWithIconBase implements IC
super.setProperties(properties);
this._button.enabled = this.enabled;
this._button.label = this.label;
this._button.title = this.title;
if (this.width) {
this._button.setWidth(this.convertSize(this.width.toString()));
}
@@ -153,7 +155,7 @@ export default class ButtonComponent extends ComponentWithIconBase implements IC
this.setPropertyFromUI<sqlops.ButtonProperties, string>(this.setFileContentProperties, newValue);
}
private setFileContentProperties(properties: sqlops.ButtonProperties, fileContent: string) : void {
private setFileContentProperties(properties: sqlops.ButtonProperties, fileContent: string): void {
properties.fileContent = fileContent;
}
@@ -164,4 +166,13 @@ export default class ButtonComponent extends ComponentWithIconBase implements IC
private setFileProperties(properties: sqlops.ButtonProperties, isFile: boolean): void {
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);
}
}

View File

@@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./card';
import { Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
import {
Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList,
} from '@angular/core';
@@ -28,11 +29,11 @@ export default class CardComponent extends ComponentWithIconBase implements ICom
private backgroundColor: string;
constructor(@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
constructor( @Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
) {
super(changeRef);
super(changeRef, el);
}
ngOnInit(): void {
@@ -70,7 +71,7 @@ export default class CardComponent extends ComponentWithIconBase implements ICom
public getClass(): string {
return (this.selectable && this.selected || this._hasFocus) ? 'model-card selected' :
'model-card unselected';
'model-card unselected';
}
public onCardHoverChanged(event: any) {
@@ -81,7 +82,7 @@ export default class CardComponent extends ComponentWithIconBase implements ICom
}
/// IComponent implementation
public setLayout (layout: any): void {
public setLayout(layout: any): void {
// TODO allow configuring the look and feel
this.layout();
}
@@ -141,7 +142,7 @@ export default class CardComponent extends ComponentWithIconBase implements ICom
public get statusColor(): string {
let status = this.getPropertyOrDefault<CardProperties, StatusIndicator>((props) => props.status, StatusIndicator.None);
switch(status) {
switch (status) {
case StatusIndicator.Ok:
return 'green';
case StatusIndicator.Warning:

View File

@@ -29,8 +29,9 @@ export default class CheckBoxComponent extends ComponentBase implements ICompone
@ViewChild('input', { read: ElementRef }) private _inputContainer: ElementRef;
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
super(changeRef);
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef) {
super(changeRef, el);
}
ngOnInit(): void {

View File

@@ -19,6 +19,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component';
import URI from 'vs/base/common/uri';
import { Builder } from 'vs/base/browser/builder';
import { IdGenerator } from 'vs/base/common/idGenerator';
import { createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom';
import * as nls from 'vs/nls';
@@ -35,8 +36,11 @@ export abstract class ComponentBase extends Disposable implements IComponent, On
private _valid: boolean = true;
protected _validations: (() => boolean | Thenable<boolean>)[] = [];
private _eventQueue: IComponentEventArgs[] = [];
private _CSSStyles: { [key: string]: string } = {};
constructor(
protected _changeRef: ChangeDetectorRef) {
protected _changeRef: ChangeDetectorRef,
protected _el: ElementRef) {
super();
}
@@ -80,11 +84,20 @@ export abstract class ComponentBase extends Disposable implements IComponent, On
public refreshDataProvider(item: any): void {
}
public updateStyles() {
let element = new Builder(this._el.nativeElement);
this._CSSStyles = this.CSSStyles;
element.style(this._CSSStyles);
}
public setProperties(properties: { [key: string]: any; }): void {
if (!properties) {
this.properties = {};
}
this.properties = properties;
if (this.CSSStyles !== this._CSSStyles) {
this.updateStyles();
}
this.layout();
this.validate();
}
@@ -140,11 +153,19 @@ export abstract class ComponentBase extends Disposable implements IComponent, On
}
public get position(): string {
return this.getPropertyOrDefault<sqlops.EditorProperties, string>((props) => props.position, '');
return this.getPropertyOrDefault<sqlops.ComponentProperties, string>((props) => props.position, '');
}
public set position(newValue: string) {
this.setPropertyFromUI<sqlops.EditorProperties, string>((properties, position) => { properties.position = position; }, newValue);
this.setPropertyFromUI<sqlops.ComponentProperties, string>((properties, position) => { properties.position = position; }, newValue);
}
public get CSSStyles(): { [key: string]: string } {
return this.getPropertyOrDefault<sqlops.ComponentProperties, { [key: string]: string }>((props) => props.CSSStyles, {});
}
public set CSSStyles(newValue: { [key: string]: string }) {
this.setPropertyFromUI<sqlops.ComponentProperties, { [key: string]: string }>((properties, CSSStyles) => { properties.CSSStyles = CSSStyles; }, newValue);
}
public convertSizeToNumber(size: number | string): number {
@@ -223,9 +244,10 @@ export abstract class ContainerBase<T> extends ComponentBase {
@ViewChildren(ModelComponentWrapper) protected _componentWrappers: QueryList<ModelComponentWrapper>;
constructor(
_changeRef: ChangeDetectorRef
_changeRef: ChangeDetectorRef,
_el: ElementRef
) {
super(_changeRef);
super(_changeRef, _el);
this.items = [];
this._validations.push(() => this.items.every(item => {
return this.modelStore.getComponent(item.descriptor.id).valid;
@@ -239,7 +261,7 @@ export abstract class ContainerBase<T> extends ComponentBase {
}
if (index !== undefined && index !== null && index >= 0 && index < this.items.length) {
this.items.splice(index, 0, new ItemDescriptor(componentDescriptor, config));
} else if(!index) {
} else if (!index) {
this.items.push(new ItemDescriptor(componentDescriptor, config));
} else {
throw new Error(nls.localize('invalidIndex', 'The index is invalid.'));

View File

@@ -22,13 +22,16 @@ export class ItemDescriptor<T> {
constructor(public descriptor: IComponentDescriptor, public config: T) { }
}
const ids = new IdGenerator('model-view-component-icon-');
export abstract class ComponentWithIconBase extends ComponentBase {
protected _iconClass: string;
protected _iconPath: IUserFriendlyIcon;
constructor(
changeRef: ChangeDetectorRef) {
super(changeRef);
changeRef: ChangeDetectorRef,
el: ElementRef, ) {
super(changeRef, el);
}
/// IComponent implementation
@@ -41,7 +44,6 @@ export abstract class ComponentWithIconBase extends ComponentBase {
if (this.iconPath && this.iconPath !== this._iconPath) {
this._iconPath = this.iconPath;
if (!this._iconClass) {
const ids = new IdGenerator('model-view-component-icon-' + Math.round(Math.random() * 1000));
this._iconClass = ids.nextId();
}

View File

@@ -2,7 +2,7 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* 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 FormContainer from './formContainer.component';
import ToolbarContainer from './toolbarContainer.component';
@@ -25,6 +25,9 @@ import EditorComponent from './editor.component';
import { registerComponentType } from 'sql/platform/dashboard/common/modelComponentRegistry';
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';
registerComponentType(FLEX_CONTAINER, ModelComponentTypes.FlexContainer, FlexContainer);

View File

@@ -64,9 +64,10 @@ export default class DeclarativeTableComponent extends ComponentBase implements
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
@Inject(IContextViewService) private contextViewService: IContextViewService
@Inject(IContextViewService) private contextViewService: IContextViewService,
@Inject(forwardRef(() => ElementRef)) el: ElementRef
) {
super(changeRef);
super(changeRef, el);
}
ngOnInit(): void {
@@ -134,7 +135,7 @@ export default class DeclarativeTableComponent extends ComponentBase implements
private onCellDataChanged(newValue: any, row: number, cell: number): void {
this.data[row][cell] = newValue;
this.data = this.data;
let newCellData : sqlops.TableCell = {
let newCellData: sqlops.TableCell = {
row: row,
column: cell,
value: newValue

View 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 : {};
}
}

View File

@@ -0,0 +1,5 @@
.divContainer {
display: block;
height: 100%;
}

View File

@@ -41,9 +41,10 @@ export default class DropDownComponent extends ComponentBase implements ICompone
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
@Inject(IContextViewService) private contextViewService: IContextViewService
@Inject(IContextViewService) private contextViewService: IContextViewService,
@Inject(forwardRef(() => ElementRef)) el: ElementRef
) {
super(changeRef);
super(changeRef, el);
}
ngOnInit(): void {

View File

@@ -41,12 +41,12 @@ export default class EditorComponent extends ComponentBase implements IComponent
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
@Inject(IInstantiationService) private _instantiationService: IInstantiationService,
@Inject(IModelService) private _modelService: IModelService,
@Inject(IModeService) private _modeService: IModeService
) {
super(changeRef);
super(changeRef, el);
}
ngOnInit(): void {
@@ -63,7 +63,7 @@ export default class EditorComponent extends ComponentBase implements IComponent
this._editor.create(this._el.nativeElement);
this._editor.setVisible(true);
let uri = this.createUri();
this._editorInput = instantiationService.createInstance(UntitledEditorInput, uri, false, 'sql', '', '');
this._editorInput = instantiationService.createInstance(UntitledEditorInput, uri, false, 'plaintext', '', '');
this._editor.setInput(this._editorInput, undefined);
this._editorInput.resolve().then(model => {
this._editorModel = model.textEditorModel;
@@ -107,7 +107,7 @@ export default class EditorComponent extends ComponentBase implements IComponent
this._editor.layout(new DOM.Dimension(
width && width > 0 ? width : DOM.getContentWidth(this._el.nativeElement),
height && height > 0 ? height : DOM.getContentHeight(this._el.nativeElement)));
let element = <HTMLElement> this._el.nativeElement;
let element = <HTMLElement>this._el.nativeElement;
element.style.position = this.position;
}
@@ -129,7 +129,6 @@ export default class EditorComponent extends ComponentBase implements IComponent
}
/// IComponent implementation
public setLayout(layout: any): void {
// TODO allow configuring the look and feel
this.layout();

View File

@@ -27,15 +27,16 @@ export default class FileBrowserTreeComponent extends ComponentBase implements I
@Input() modelStore: IModelStore;
private _treeView: FileBrowserTreeView;
private _viewModel: FileBrowserViewModel;
private _fileFilters: [{label: string, filters: string[]}] = [
private _fileFilters: [{ label: string, filters: string[] }] = [
{ label: 'All Files', filters: ['*'] }
];
@ViewChild('fileBrowserTree', { read: ElementRef }) private _treeContainer: ElementRef;
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(IInstantiationService) private _instantiationService: IInstantiationService) {
super(changeRef);
@Inject(IInstantiationService) private _instantiationService: IInstantiationService,
@Inject(forwardRef(() => ElementRef)) el: ElementRef) {
super(changeRef, el);
}
ngOnInit(): void {

View File

@@ -45,8 +45,11 @@ export default class FlexContainer extends ContainerBase<FlexItemLayout> impleme
private _width: string;
private _position: string;
constructor(@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
super(changeRef);
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef
) {
super(changeRef, el);
this._flexFlow = ''; // default
this._justifyContent = ''; // default
}

View File

@@ -106,8 +106,9 @@ export default class FormContainer extends ContainerBase<FormItemLayout> impleme
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
super(changeRef);
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef) {
super(changeRef, el);
}
ngOnInit(): void {

View File

@@ -45,8 +45,9 @@ export default class GroupContainer extends ContainerBase<GroupLayout> implement
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
super(changeRef);
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef) {
super(changeRef, el);
}
ngOnInit(): void {

View File

@@ -42,9 +42,10 @@ export default class InputBoxComponent extends ComponentBase implements ICompone
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
@Inject(IContextViewService) private contextViewService: IContextViewService
@Inject(IContextViewService) private contextViewService: IContextViewService,
@Inject(forwardRef(() => ElementRef)) el: ElementRef
) {
super(changeRef);
super(changeRef, el);
}
ngOnInit(): void {

View File

@@ -37,9 +37,10 @@ export default class ListBoxComponent extends ComponentBase implements IComponen
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
@Inject(IContextViewService) private contextViewService: IContextViewService,
@Inject(IClipboardService) private clipboardService: IClipboardService
@Inject(IClipboardService) private clipboardService: IClipboardService,
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
) {
super(changeRef);
super(changeRef, el);
}
ngOnInit(): void {

View File

@@ -35,8 +35,9 @@ export default class LoadingComponent extends ComponentBase implements IComponen
@ViewChild('childElement', { read: ElementRef }) private _childElement: ElementRef;
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
super(changeRef);
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef) {
super(changeRef, el);
this._validations.push(() => {
if (!this._component) {
return true;

View File

@@ -3,16 +3,50 @@
* 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 { 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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
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 {
public static ID: string = 'workbench.editorinputs.ModelViewEditorInput';
@@ -20,14 +54,15 @@ export class ModelViewInput extends EditorInput {
private _dialogPaneContainer: HTMLElement;
private _dialogPane: DialogPane;
constructor(private _title: string, private _modelViewId: string,
constructor(private _title: string, private _model: ModelViewInputModel,
private _options: sqlops.ModelViewEditorOptions,
@IInstantiationService private _instantiationService: IInstantiationService,
@IPartService private readonly _partService: IPartService
) {
super();
this._model.onDidChangeDirty(() => this._onDidChangeDirty.fire());
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);
}
@@ -37,7 +72,7 @@ export class ModelViewInput extends EditorInput {
}
public get modelViewId(): string {
return this._modelViewId;
return this._model.modelViewId;
}
public getTypeId(): string {
@@ -85,6 +120,31 @@ export class ModelViewInput extends EditorInput {
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 {
if (this._dialogPane) {
this._dialogPane.dispose();
@@ -93,6 +153,9 @@ export class ModelViewInput extends EditorInput {
this._container.remove();
this._container = undefined;
}
if (this._model) {
this._model.dispose();
}
super.dispose();
}
}

View File

@@ -33,8 +33,9 @@ export default class RadioButtonComponent extends ComponentBase implements IComp
@ViewChild('input', { read: ElementRef }) private _inputContainer: ElementRef;
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
super(changeRef);
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef) {
super(changeRef, el);
}
ngOnInit(): void {

View File

@@ -35,8 +35,9 @@ export default class TableComponent extends ComponentBase implements IComponent,
@ViewChild('table', { read: ElementRef }) private _inputContainer: ElementRef;
constructor(
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService) {
super(changeRef);
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
@Inject(forwardRef(() => ElementRef)) el: ElementRef) {
super(changeRef, el);
}
ngOnInit(): void {

View File

@@ -6,7 +6,7 @@
import 'vs/css!./radioButton';
import {
Component, Input, Inject, ChangeDetectorRef, forwardRef,
OnDestroy, AfterViewInit
OnDestroy, AfterViewInit, ElementRef
} from '@angular/core';
import * as sqlops from 'sqlops';
@@ -26,8 +26,9 @@ export default class TextComponent extends ComponentBase implements IComponent,
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
super(changeRef);
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef) {
super(changeRef, el);
}
ngOnInit(): void {

View File

@@ -29,7 +29,7 @@ export class ToolbarItem {
template: `
<div #container *ngIf="items" [class]="toolbarClass" >
<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" >
{{getItemTitle(item)}}
</div>
@@ -52,8 +52,9 @@ export default class ToolbarContainer extends ContainerBase<ToolbarItemConfig> i
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
super(changeRef);
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef) {
super(changeRef, el);
this._orientation = Orientation.Horizontal;
}
@@ -89,7 +90,7 @@ export default class ToolbarContainer extends ContainerBase<ToolbarItemConfig> i
}
public get paddingTop(): string {
return this.isHorizontal() ? '' : '10px';
return this.isHorizontal() ? '' : '';
}
public get toolbarClass(): string {

View File

@@ -30,6 +30,13 @@
padding-left: 10px;
}
.modelview-toolbar-container.toolbar-vertical .modelview-toolbar-item {
flex: 0 0;
flex-direction: row;
display: flex;
padding-left: 0px;
}
.modelview-toolbar-container .modelview-toolbar-title {
padding: 4px;
font-size: 14px;
@@ -46,4 +53,21 @@
padding-left: 15px;
background-size: 11px;
margin-right: 0.3em;
}
}
/* Vertical button handling */
.modelview-toolbar-container.toolbar-vertical .modelview-toolbar-component modelview-button .monaco-text-button.icon {
padding: 22px 16px 22px 16px;
background-size: 22px;
margin-right: 0.3em;
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);
}

View File

@@ -55,8 +55,10 @@ export default class TreeComponent extends ComponentBase implements IComponent,
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
@Inject(IContextViewService) private contextViewService: IContextViewService,
@Inject(IInstantiationService) private _instantiationService: IInstantiationService) {
super(changeRef);
@Inject(IInstantiationService) private _instantiationService: IInstantiationService,
@Inject(forwardRef(() => ElementRef)) el: ElementRef
) {
super(changeRef, el);
}
ngOnInit(): void {
@@ -112,7 +114,7 @@ export default class TreeComponent extends ComponentBase implements IComponent,
this._tree.domFocus();
this._register(this._tree);
this._register(attachListStyler(this._tree, this.themeService));
this._register(this._tree.onDidChangeSelection( e => {
this._register(this._tree.onDidChangeSelection(e => {
this._dataProvider.onNodeSelected(e.selection);
}));
this._tree.refresh();

View File

@@ -29,11 +29,6 @@ export class TreeViewDataProvider extends vsTreeView.TreeViewDataProvider implem
}
}
refresh(itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeComponentItem }) {
}
getChildren(element?: ITreeComponentItem): TPromise<ITreeComponentItem[]> {
return undefined;
}
}

View File

@@ -26,6 +26,13 @@ import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } fro
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
function reviveWebviewOptions(options: vscode.WebviewOptions): vscode.WebviewOptions {
return {
...options,
localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(URI.revive) : undefined
};
}
@Component({
template: '',
selector: 'modelview-webview-component'
@@ -46,7 +53,7 @@ export default class WebViewComponent extends ComponentBase implements IComponen
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
@Inject(IPartService) private partService: IPartService,
@Inject(IThemeService) private themeService: IThemeService,
@Inject(IEnvironmentService) private environmentService: IEnvironmentService,
@@ -56,7 +63,7 @@ export default class WebViewComponent extends ComponentBase implements IComponen
@Inject(IInstantiationService) private instantiationService: IInstantiationService,
@Inject(IContextKeyService) contextKeyService: IContextKeyService
) {
super(changeRef);
super(changeRef, el);
}
ngOnInit(): void {
@@ -132,7 +139,7 @@ export default class WebViewComponent extends ComponentBase implements IComponen
/// IComponent implementation
public layout(): void {
let element = <HTMLElement> this._el.nativeElement;
let element = <HTMLElement>this._el.nativeElement;
element.style.position = this.position;
this._webview.layout();
}
@@ -192,6 +199,7 @@ export default class WebViewComponent extends ComponentBase implements IComponen
private getExtendedOptions(): WebviewOptions {
let options = this.options || { enableScripts: true };
options = reviveWebviewOptions(options);
return {
allowScripts: options.enableScripts,
allowSvgs: true,
@@ -208,4 +216,5 @@ export default class WebViewComponent extends ComponentBase implements IComponen
}
return rootPaths;
}
}

View File

@@ -72,6 +72,8 @@ export interface IObjectExplorerService {
getActiveConnectionNodes(): TreeNode[];
getTreeNode(connectionId: string, nodePath: string): Thenable<TreeNode>;
refreshNodeInView(connectionId: string, nodePath: string): Thenable<TreeNode>;
}
interface SessionStatus {
@@ -476,6 +478,20 @@ export class ObjectExplorerService implements IObjectExplorerService {
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> {
treeNode = await this.getUpdatedTreeNode(treeNode);
let expandNode = this.getTreeItem(treeNode);

View File

@@ -39,7 +39,7 @@ const viewletDescriptor = new ViewletDescriptor(
VIEWLET_ID,
'Servers',
'connectionViewlet',
-100
0
);
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);

View File

@@ -138,7 +138,7 @@ export class ServerTreeView {
let expandGroups: boolean = self._configurationService.getValue(SERVER_GROUP_CONFIG)[SERVER_GROUP_AUTOEXPAND_CONFIG];
if (expandGroups) {
self._tree.expandAll(ConnectionProfileGroup.getSubgroups(root));
self._tree.expandAll(ConnectionProfileGroup.getSubgroups(root));
}
if (root && !root.hasValidConnections) {
@@ -244,6 +244,10 @@ export class ServerTreeView {
TreeUpdateUtils.registeredServerUpdate(this._tree, this._connectionManagementService);
}
public refreshElement(element: any): Thenable<void> {
return this._tree.refresh(element);
}
/**
* Filter connections based on view (recent/active)
*/

View File

@@ -10,6 +10,22 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { EditorInput } from 'vs/workbench/common/editor';
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';
export class ResultsViewState {
public gridPanelState: GridPanelState = new GridPanelState();
public messagePanelState: MessagePanelState = new MessagePanelState();
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>();
}
/**
* Input for the QueryResultsEditor. This input helps with logic for the viewing and editing of
* data in the results grid.
@@ -29,6 +45,8 @@ export class QueryResultsInput extends EditorInput {
public readonly onRestoreViewStateEmitter = new Emitter<void>();
public readonly onSaveViewStateEmitter = new Emitter<void>();
public readonly state = new ResultsViewState();
constructor(private _uri: string) {
super();
this._visible = false;

View File

@@ -82,12 +82,12 @@ export class RowCountStatusBarItem implements IStatusbarItem {
}
private _displayValue(runner: QueryRunner) {
let number = runner.batchSets.reduce((p, c) => {
let rowCount = runner.batchSets.reduce((p, c) => {
return p + c.resultSetSummaries.reduce((rp, rc) => {
return rp + rc.rowCount;
}, 0);
}, 0);
this._flavorElement.innerText = nls.localize('rowCount', "{0} rows", number);
this._flavorElement.innerText = nls.localize('rowCount', "{0} rows", rowCount);
show(this._flavorElement);
}
}

View File

@@ -11,13 +11,14 @@ import { localize } from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
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 { SaveFormat } from 'sql/parts/grid/common/interfaces';
import { Table } from 'sql/base/browser/ui/table/table';
import { GridTableState } from 'sql/parts/query/editor/gridPanel';
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 {
cell: { row: number; cell: number; };
@@ -26,6 +27,7 @@ export interface IGridActionContext {
batchId: number;
resultId: number;
table: Table<any>;
selectionModel: CellSelectionModel<any>;
tableState: GridTableState;
}
@@ -34,6 +36,14 @@ export interface IMessagesActionContext {
tree: ITree;
}
function mapForNumberColumn(ranges: Slick.Range[]): Slick.Range[] {
if (ranges) {
return ranges.map(e => new Slick.Range(e.fromRow, e.fromCell - 1, e.toRow, e.toCell ? e.toCell - 1 : undefined));
} else {
return undefined;
}
}
export class SaveResultAction extends Action {
public static SAVECSV_ID = 'grid.saveAsCsv';
public static SAVECSV_LABEL = localize('saveAsCsv', 'Save As CSV');
@@ -51,13 +61,19 @@ export class SaveResultAction extends Action {
id: string,
label: string,
icon: string,
private format: SaveFormat
private format: SaveFormat,
private accountForNumberColumn = true
) {
super(id, label, icon);
}
public run(context: IGridActionContext): TPromise<boolean> {
context.runner.serializeResults(context.batchId, context.resultId, this.format, context.selection);
if (this.accountForNumberColumn) {
context.runner.serializeResults(context.batchId, context.resultId, this.format,
mapForNumberColumn(context.selection));
} else {
context.runner.serializeResults(context.batchId, context.resultId, this.format, context.selection);
}
return TPromise.as(true);
}
}
@@ -73,12 +89,19 @@ export class CopyResultAction extends Action {
id: string,
label: string,
private copyHeader: boolean,
private accountForNumberColumn = true
) {
super(id, label);
}
public run(context: IGridActionContext): TPromise<boolean> {
context.runner.copyResults(context.selection, context.batchId, context.resultId, this.copyHeader);
if (this.accountForNumberColumn) {
context.runner.copyResults(
mapForNumberColumn(context.selection),
context.batchId, context.resultId, this.copyHeader);
} else {
context.runner.copyResults(context.selection, context.batchId, context.resultId, this.copyHeader);
}
return TPromise.as(true);
}
}
@@ -92,7 +115,7 @@ export class SelectAllGridAction extends Action {
}
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);
}
}
@@ -146,13 +169,13 @@ export class MaximizeTableAction extends Action {
}
}
export class MinimizeTableAction extends Action {
public static ID = 'grid.minimize';
public static LABEL = localize('minimize', 'Minimize');
export class RestoreTableAction extends Action {
public static ID = 'grid.restore';
public static LABEL = localize('restore', 'Restore');
public static ICON = 'exitFullScreen';
constructor() {
super(MinimizeTableAction.ID, MinimizeTableAction.LABEL, MinimizeTableAction.ICON);
super(RestoreTableAction.ID, RestoreTableAction.LABEL, RestoreTableAction.ICON);
}
public run(context: IGridActionContext): TPromise<boolean> {

View File

@@ -8,10 +8,9 @@
import { localize } from 'vs/nls';
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 { DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/types/lineChart.component';
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);

View File

@@ -15,7 +15,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
export class ChartTab implements IPanelTab {
public readonly title = localize('chartTabTitle', 'Chart');
public readonly identifier = generateUuid();
public readonly identifier = 'ChartTab';
public readonly view: ChartView;
constructor(@IInstantiationService instantiationService: IInstantiationService) {

View File

@@ -12,11 +12,11 @@ import { Insight } from './insights/insight';
import QueryRunner from 'sql/parts/query/execution/queryRunner';
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
import { ChartOptions, IChartOption, ControlType } from './chartOptions';
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox';
import { IInsightOptions } from './insights/interfaces';
import { CopyAction, SaveImageAction, CreateInsightAction, IChartActionContext } from './actions';
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
import { ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { Dimension, $, getContentHeight, getContentWidth } from 'vs/base/browser/dom';
import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
@@ -27,6 +27,14 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { attachSelectBoxStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
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 {
constructor(object, handler);
@@ -43,6 +51,8 @@ export class ChartView implements IPanelView {
private _copyAction: CopyAction;
private _saveAction: SaveImageAction;
private _state: ChartState;
private options: IInsightOptions = {
type: ChartType.Bar
};
@@ -61,7 +71,7 @@ export class ChartView implements IPanelView {
private chartingContainer: HTMLElement;
private optionDisposables: IDisposable[] = [];
private optionMap: { [x: string]: HTMLElement } = {};
private optionMap: { [x: string]: { element: HTMLElement; set: (val) => void } } = {};
constructor(
@IContextViewService private _contextViewService: IContextViewService,
@@ -95,6 +105,10 @@ export class ChartView implements IPanelView {
}
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) {
self.taskbar.context = <IChartActionContext>{ options: self.options, insight: self.insight ? self.insight.insight : undefined };
@@ -138,6 +152,7 @@ export class ChartView implements IPanelView {
}
public chart(dataId: { batchId: number, resultId: number }) {
this.state.dataId = dataId;
this._currentData = dataId;
this.shouldGraph();
}
@@ -172,7 +187,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
}
}
@@ -180,7 +195,9 @@ export class ChartView implements IPanelView {
private buildOptions() {
dispose(this.optionDisposables);
this.optionDisposables = [];
this.optionMap = {};
this.optionMap = {
'type': this.optionMap['type']
};
new Builder(this.typeControls).clearChildren();
this.updateActionbar();
@@ -200,9 +217,9 @@ export class ChartView implements IPanelView {
let option = ChartOptions[this.options.type].find(e => e.configEntry === key);
if (option && option.if) {
if (option.if(this.options)) {
new Builder(this.optionMap[key]).show();
new Builder(this.optionMap[key].element).show();
} else {
new Builder(this.optionMap[key]).hide();
new Builder(this.optionMap[key].element).hide();
}
}
}
@@ -211,6 +228,7 @@ export class ChartView implements IPanelView {
private updateActionbar() {
if (this.insight && this.insight.isCopyable) {
this.taskbar.context = { insight: this.insight.insight, options: this.options };
this.taskbar.setContent([
{ action: this._createInsightAction },
{ action: this._copyAction },
@@ -226,57 +244,104 @@ export class ChartView implements IPanelView {
label.innerText = option.label;
let optionContainer = $('div.option-container');
optionContainer.appendChild(label);
let setFunc: (val) => void;
let value = this.state ? this.state.options[option.configEntry] || option.default : option.default;
switch (option.type) {
case ControlType.checkbox:
let checkbox = new Checkbox(optionContainer, {
label: '',
ariaLabel: option.label,
checked: option.default,
checked: value,
onChange: () => {
if (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;
case ControlType.combo:
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.onDidSelect(e => {
if (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));
break;
case ControlType.input:
let input = new InputBox(optionContainer, this._contextViewService);
input.value = option.default || '';
input.value = value || '';
input.onDidChange(e => {
if (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));
break;
case ControlType.numberInput:
let numberInput = new InputBox(optionContainer, this._contextViewService, { type: 'number' });
numberInput.value = option.default || '';
numberInput.value = value || '';
numberInput.onDidChange(e => {
if (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)) {
input.value = val;
}
};
this.optionDisposables.push(attachInputBoxStyler(numberInput, this._themeService));
break;
}
this.optionMap[option.configEntry] = optionContainer;
this.optionMap[option.configEntry] = { element: optionContainer, set: setFunc };
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.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;
}
}

View File

@@ -13,9 +13,9 @@ import * as colors from 'vs/platform/theme/common/colorRegistry';
import { editorLineNumbers } from 'vs/editor/common/view/editorColorRegistry';
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 { IInsightOptions, IInsight } from './interfaces';
import { ChartType, DataDirection, LegendPosition } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
const noneLineGraphs = [ChartType.Doughnut, ChartType.Pie];

View File

@@ -6,15 +6,15 @@
'use strict';
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 { Builder } from 'vs/base/browser/builder';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { DataDirection, ChartType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
import { ImageInsight } from './imageInsight';
import { TableInsight } from './tableInsight';
import { IInsightOptions, IInsight, InsightType, IInsightCtor } from './interfaces';
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';
const defaultOptions: IInsightOptions = {

View File

@@ -4,11 +4,10 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Dimension } from 'vs/base/browser/dom';
import { IInsightData } from 'sql/parts/dashboard/widgets/insights/interfaces';
import { ChartType, LegendPosition, DataDirection } from 'sql/parts/dashboard/widgets/insights/views/charts/chartInsight.component';
import { Dimension } from 'vs/base/browser/dom';
import { DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/types/lineChart.component';
import { DataDirection, ChartType, LegendPosition, DataType } from 'sql/parts/dashboard/widgets/insights/views/charts/interfaces';
export interface IInsightOptions {
type: InsightType | ChartType;

View File

@@ -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 { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin';
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 { RowNumberColumn } from 'sql/base/browser/ui/table/plugins/rowNumberColumn.plugin';
import { escape } from 'sql/base/common/strings';
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';
@@ -38,20 +40,26 @@ import { Dimension, getContentWidth } from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IAction } from 'vs/base/common/actions';
const ROW_HEIGHT = 29;
const HEADER_HEIGHT = 26;
const MIN_GRID_HEIGHT_ROWS = 8;
const ESTIMATED_SCROLL_BAR_HEIGHT = 10;
const BOTTOM_PADDING = 5;
const BOTTOM_PADDING = 15;
const ACTIONBAR_WIDTH = 26;
// minimum height needed to show the full actionbar
const ACTIONBAR_HEIGHT = 100;
// 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 {
canBeMaximized: boolean;
@@ -65,13 +73,29 @@ export class GridTableState {
private _onMaximizedChange = new Emitter<boolean>();
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) {
if (state) {
this._maximized = state.maximized;
this.canBeMaximized = state.canBeMaximized;
private _canBeMaximized: boolean;
/* The top row of the current scroll */
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 {
@@ -85,10 +109,6 @@ export class GridTableState {
this._maximized = val;
this._onMaximizedChange.fire(val);
}
public clone(): GridTableState {
return new GridTableState({ canBeMaximized: this.canBeMaximized, maximized: this.maximized });
}
}
export class GridPanel extends ViewletPanel {
@@ -102,6 +122,7 @@ export class GridPanel extends ViewletPanel {
private runner: QueryRunner;
private maximizedGrid: GridTable<any>;
private _state: GridPanelState;
constructor(
options: IViewletPanelOptions,
@@ -113,6 +134,16 @@ export class GridPanel extends ViewletPanel {
) {
super(options, keybindingService, contextMenuService, configurationService);
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 {
@@ -150,6 +181,10 @@ export class GridPanel extends ViewletPanel {
this.maximumBodySize = this.tables.reduce((p, c) => {
return p + c.maximumSize;
}, 0);
if (this.state && this.state.scrollPosition) {
this.splitView.setScrollPosition(this.state.scrollPosition);
}
}
private addResultSet(resultSet: sqlops.ResultSetSummary | sqlops.ResultSetSummary[]) {
@@ -163,8 +198,18 @@ export class GridPanel extends ViewletPanel {
let tables: GridTable<any>[] = [];
for (let set of resultsToAdd) {
let tableState = new GridTableState();
let table = this.instantiationService.createInstance(GridTable, this.runner, tableState, set);
let tableState: GridTableState;
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 => {
if (e) {
this.maximizeTable(table.id);
@@ -215,10 +260,6 @@ export class GridPanel extends ViewletPanel {
}
}
public layout(size: number) {
this.splitView.layout(size);
}
private minimizeTables(): void {
if (this.maximizedGrid) {
this.maximizedGrid.state.maximized = false;
@@ -227,6 +268,24 @@ export class GridPanel extends ViewletPanel {
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 {
@@ -245,13 +304,14 @@ class GridTable<T> extends Disposable implements IView {
public id = generateUuid();
readonly element: HTMLElement = this.container;
private _state: GridTableState;
// 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(
private runner: QueryRunner,
public state: GridTableState,
private resultSet: sqlops.ResultSetSummary,
public readonly resultSet: sqlops.ResultSetSummary,
@IContextMenuService private contextMenuService: IContextMenuService,
@IInstantiationService private instantiationService: IInstantiationService,
@IEditorService private editorService: IEditorService,
@@ -260,7 +320,7 @@ class GridTable<T> extends Disposable implements IView {
super();
this.container.style.width = '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.columns = this.resultSet.columnInfo.map((c, i) => {
@@ -295,12 +355,24 @@ class GridTable<T> extends Disposable implements IView {
this.renderGridDataRowsRange(startIndex, count);
});
let numberColumn = new RowNumberColumn({ numberOfRows: this.resultSet.rowCount });
let copyHandler = new CopyKeybind();
copyHandler.onCopy(e => {
new CopyResultAction(CopyResultAction.COPY_ID, CopyResultAction.COPY_LABEL, false).run(this.generateContext());
});
this.columns.unshift(numberColumn.getColumnDefinition());
this.table = this._register(new Table(tableContainer, { dataProvider: new AsyncDataProvider(collection), columns: this.columns }, { rowHeight: ROW_HEIGHT, showRowNumber: true }));
let tableOptions: Slick.GridOptions<T> = {
rowHeight: ROW_HEIGHT,
showRowNumber: true,
forceFitColumns: false,
defaultColumnWidth: 120
};
this.table = this._register(new Table(tableContainer, { dataProvider: new AsyncDataProvider(collection), columns: this.columns }, tableOptions));
this.table.setSelectionModel(this.selectionModel);
this.table.registerPlugin(new MouseWheelSupport());
this.table.registerPlugin(new AutoColumnSize());
this.table.registerPlugin(copyHandler);
this.table.registerPlugin(numberColumn);
this.table.registerPlugin(new AdditionalKeyBindings());
this._register(this.table.onContextMenu(this.contextMenu, this));
this._register(this.table.onClick(this.onTableClick, this));
@@ -308,22 +380,7 @@ class GridTable<T> extends Disposable implements IView {
this.table.style(this.styles);
}
let actions = [];
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 actions = this.getCurrentActions();
let actionBarContainer = document.createElement('div');
actionBarContainer.style.width = ACTIONBAR_WIDTH + 'px';
@@ -340,7 +397,58 @@ class GridTable<T> extends Disposable implements IView {
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.selectionModel.onSelectedRangesChanged.subscribe(e => {
if (this.state) {
this.state.selection = this.selectionModel.getSelectedRanges();
}
});
this.table.grid.onScroll.subscribe(e => {
if (this.state) {
this.state.scrollPosition = this.table.grid.getViewport().top;
}
});
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) {
this.table.grid.scrollRowToTop(this.state.scrollPosition);
}
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) {
@@ -356,6 +464,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 {
if (!this.table) {
this.build();
@@ -368,18 +518,18 @@ class GridTable<T> extends Disposable implements IView {
this.table.layout(
new Dimension(
getContentWidth(this.container) - ACTIONBAR_WIDTH,
size - BOTTOM_PADDING
size
)
);
}
public get minimumSize(): number {
// 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 {
return Math.max(this.maxSize, ACTIONBAR_HEIGHT);
return Math.max(this.maxSize, ACTIONBAR_HEIGHT + BOTTOM_PADDING);
}
private loadData(offset: number, count: number): Thenable<T[]> {
@@ -403,7 +553,6 @@ class GridTable<T> extends Disposable implements IView {
}
private contextMenu(e: ITableMouseEvent): void {
const selection = this.selectionModel.getSelectedRanges();
const { cell } = e;
this.contextMenuService.showContextMenu({
getAnchor: () => e.anchor,
@@ -421,7 +570,7 @@ class GridTable<T> extends Disposable implements IView {
if (this.state.canBeMaximized) {
if (this.state.maximized) {
actions.splice(1, 0, new MinimizeTableAction());
actions.splice(1, 0, new RestoreTableAction());
} else {
actions.splice(1, 0, new MaximizeTableAction());
}
@@ -430,15 +579,7 @@ class GridTable<T> extends Disposable implements IView {
return TPromise.as(actions);
},
getActionsContext: () => {
return <IGridActionContext>{
cell,
selection,
runner: this.runner,
batchId: this.resultSet.batchId,
resultId: this.resultSet.id,
table: this.table,
tableState: this.state
};
return this.generateContext(cell);
}
});
}

View File

@@ -13,18 +13,28 @@
word-break: break-all;
}
.monaco-workbench .message-tree .monaco-tree .monaco-tree-rows>.monaco-tree-row {
cursor: default;
}
.message-tree .time-stamp {
width: 100px;
display: inline-block;
}
.message-tree .message,
.message-tree .batch-start {
.message-tree .batch-start,
.message-tree .error-message {
display: inline-block;
}
.message-tree .batch-start {
text-decoration: underline;
cursor: pointer;
}
.message-tree .error-message {
color: red;
}
.message-tree .batch-start:hover {

View File

@@ -0,0 +1,5 @@
.monaco-select-box {
cursor: pointer;
min-width: 150px;
padding: 2px;
}

View File

@@ -8,7 +8,7 @@ import 'vs/css!./media/messagePanel';
import { IMessagesActionContext, SelectAllMessagesAction, CopyMessagesAction } from './actions';
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 { IDataSource, ITree, IRenderer, ContextMenuEvent } from 'vs/base/parts/tree/browser/tree';
@@ -27,7 +27,6 @@ import { IMouseEvent } from 'vs/base/browser/mouseEvent';
import { $ } from 'vs/base/browser/builder';
import { isArray } from 'vs/base/common/types';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { localize } from 'vs/nls';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditor } from 'vs/editor/common/editorCommon';
@@ -56,9 +55,15 @@ interface IBatchTemplate extends IMessageTemplate {
const TemplateIds = {
MESSAGE: 'message',
BATCH: 'batch',
MODEL: 'model'
MODEL: 'model',
ERROR: 'error'
};
export class MessagePanelState {
public scrollPosition: number;
public collapsed = false;
}
export class MessagePanel extends ViewletPanel {
private ds = new MessageDataSource();
private renderer = new MessageRenderer();
@@ -67,6 +72,7 @@ export class MessagePanel extends ViewletPanel {
private container = $('div message-tree').getHTMLElement();
private queryRunnerDisposables: IDisposable[] = [];
private _state: MessagePanelState;
private tree: ITree;
@@ -86,6 +92,16 @@ export class MessagePanel extends ViewletPanel {
renderer: this.renderer,
controller: this.controller
}, { 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 {
@@ -99,8 +115,12 @@ export class MessagePanel extends ViewletPanel {
protected layoutBody(size: number): void {
const previousScrollPosition = this.tree.getScrollPosition();
this.tree.layout(size);
if (previousScrollPosition === 1) {
this.tree.setScrollPosition(1);
if (this.state && this.state.scrollPosition) {
this.tree.setScrollPosition(this.state.scrollPosition);
} else {
if (previousScrollPosition === 1) {
this.tree.setScrollPosition(1);
}
}
}
@@ -113,17 +133,30 @@ export class MessagePanel extends ViewletPanel {
}
private onMessage(message: IResultMessage | IResultMessage[]) {
let hasError = false;
if (isArray(message)) {
hasError = message.find(e => e.isError) ? true : false;
this.model.messages.push(...message);
} else {
hasError = message.isError;
this.model.messages.push(message);
}
const previousScrollPosition = this.tree.getScrollPosition();
this.tree.refresh(this.model).then(() => {
if (previousScrollPosition === 1) {
if (hasError) {
this.setExpanded(true);
}
if (this.state.scrollPosition) {
this.tree.refresh(this.model).then(() => {
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() {
@@ -131,6 +164,17 @@ export class MessagePanel extends ViewletPanel {
this.model.totalExecuteMessage = undefined;
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 {
@@ -176,6 +220,8 @@ class MessageRenderer implements IRenderer {
return TemplateIds.MODEL;
} else if (element.selection) {
return TemplateIds.BATCH;
} else if (element.isError) {
return TemplateIds.ERROR;
} else {
return TemplateIds.MESSAGE;
}
@@ -191,15 +237,19 @@ class MessageRenderer implements IRenderer {
const timeStamp = $('div.time-stamp').appendTo(container).getHTMLElement();
const message = $('div.batch-start').appendTo(container).getHTMLElement();
return { message, timeStamp };
} else if (templateId === TemplateIds.ERROR) {
$('div.time-stamp').appendTo(container);
const message = $('div.error-message').appendTo(container).getHTMLElement();
return { message };
} else {
return undefined;
}
}
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;
data.message.innerText = element.message;
data.message.innerText = element.message.replace(/(\r\n|\n|\r)/g, ' ');
} else if (templateId === TemplateIds.BATCH) {
let data = templateData as IBatchTemplate;
data.timeStamp.innerText = element.time;

View File

@@ -43,7 +43,7 @@ import {
import { IQueryModelService } from 'sql/parts/query/execution/queryModel';
import { IEditorDescriptorService } from 'sql/parts/query/editor/editorDescriptorService';
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
import { attachEditableDropdownStyler } from 'sql/common/theme/styler';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
@@ -96,7 +96,8 @@ export class QueryEditor extends BaseEditor {
@IQueryModelService private _queryModelService: IQueryModelService,
@IEditorDescriptorService private _editorDescriptorService: IEditorDescriptorService,
@IContextKeyService contextKeyService: IContextKeyService,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@IConfigurationService private _configurationService: IConfigurationService
) {
super(QueryEditor.ID, _telemetryService, themeService);
@@ -293,7 +294,7 @@ export class QueryEditor extends BaseEditor {
let input = <QueryInput>this.input;
this._createResultsEditorContainer();
this._createEditor(<QueryResultsInput>input.results, this._resultsEditorContainer)
this._createEditor(<QueryResultsInput>input.results, this._resultsEditorContainer, this.group)
.then(result => {
this._onResultsEditorCreated(<any>result, input.results, this.options);
this.resultsEditorVisibility = true;
@@ -446,6 +447,16 @@ export class QueryEditor extends BaseEditor {
this._estimatedQueryPlanAction = this._instantiationService.createInstance(EstimatedQueryPlanAction, this);
this._actualQueryPlanAction = this._instantiationService.createInstance(ActualQueryPlanAction, this);
this.setTaskbarContent();
this._configurationService.onDidChangeConfiguration(e => {
if (e.affectedKeys.includes('workbench.enablePreviewFeatures')) {
this.setTaskbarContent();
}
});
}
private setTaskbarContent(): void {
// Create HTML Elements for the taskbar
let separator = Taskbar.createTaskbarSeparator();
@@ -460,6 +471,13 @@ export class QueryEditor extends BaseEditor {
{ element: separator },
{ action: this._estimatedQueryPlanAction }
];
// Remove the estimated query plan action if preview features are not enabled
let previewFeaturesEnabled = this._configurationService.getValue('workbench')['enablePreviewFeatures'];
if (!previewFeaturesEnabled) {
content = content.slice(0, -2);
}
this._taskbar.setContent(content);
}
@@ -481,7 +499,7 @@ export class QueryEditor extends BaseEditor {
public get listDatabasesActionItem(): ListDatabasesActionItem {
if (!this._listDatabasesActionItem) {
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;
}
@@ -537,8 +555,8 @@ export class QueryEditor extends BaseEditor {
if (this._isResultsEditorVisible()) {
createEditors = () => {
return TPromise.join([
this._createEditor(<QueryResultsInput>newInput.results, this._resultsEditorContainer),
this._createEditor(<UntitledEditorInput>newInput.sql, this._sqlEditorContainer)
this._createEditor(<QueryResultsInput>newInput.results, this._resultsEditorContainer, this.group),
this._createEditor(<UntitledEditorInput>newInput.sql, this._sqlEditorContainer, this.group)
]);
};
onEditorsCreated = (result: IEditor[]) => {
@@ -551,7 +569,7 @@ export class QueryEditor extends BaseEditor {
// If only the sql editor exists, create a promise and wait for the sql editor to be created
} else {
createEditors = () => {
return this._createEditor(<UntitledEditorInput>newInput.sql, this._sqlEditorContainer);
return this._createEditor(<UntitledEditorInput>newInput.sql, this._sqlEditorContainer, this.group);
};
onEditorsCreated = (result: TextResourceEditor) => {
return TPromise.join([
@@ -583,7 +601,7 @@ export class QueryEditor extends BaseEditor {
/**
* Create a single editor based on the type of the given EditorInput.
*/
private _createEditor(editorInput: EditorInput, container: HTMLElement): TPromise<BaseEditor> {
private _createEditor(editorInput: EditorInput, container: HTMLElement, group: IEditorGroup): TPromise<BaseEditor> {
const descriptor = this._editorDescriptorService.getEditor(editorInput);
if (!descriptor) {
return TPromise.wrapError(new Error(strings.format('Can not find a registered editor for the input {0}', editorInput)));
@@ -591,7 +609,7 @@ export class QueryEditor extends BaseEditor {
let editor = descriptor.instantiate(this._instantiationService);
editor.create(container);
editor.setVisible(this.isVisible(), editor.group);
editor.setVisible(this.isVisible(), group);
return TPromise.as(editor);
}

View File

@@ -93,6 +93,7 @@ export class QueryResultsEditor extends BaseEditor {
protected _input: QueryResultsInput;
private resultsView: QueryResultsView;
private styleSheet = DOM.createStyleSheet();
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@@ -103,12 +104,13 @@ export class QueryResultsEditor extends BaseEditor {
) {
super(QueryResultsEditor.ID, telemetryService, themeService);
this._rawOptions = BareResultsGridInfo.createFromRawSettings(this._configurationService.getValue('resultsGrid'), getZoomLevel());
// this._configurationService.onDidChangeConfiguration(e => {
// if (e.affectsConfiguration('resultsGrid')) {
// this._rawOptions = BareResultsGridInfo.createFromRawSettings(this._configurationService.getValue('resultsGrid'), getZoomLevel());
// this.applySettings();
// }
// });
this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('resultsGrid')) {
this._rawOptions = BareResultsGridInfo.createFromRawSettings(this._configurationService.getValue('resultsGrid'), getZoomLevel());
this.applySettings();
}
});
this.applySettings();
}
public get input(): QueryResultsInput {
@@ -116,23 +118,20 @@ export class QueryResultsEditor extends BaseEditor {
}
private applySettings() {
if (this.input && this.input.container) {
if (!this.input.css) {
this.input.css = DOM.createStyleSheet(this.input.container);
}
let cssRuleText = '';
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 cssRuleText = '';
if (types.isNumber(this._rawOptions.cellPadding)) {
cssRuleText = this._rawOptions.cellPadding + 'px';
} else {
cssRuleText = this._rawOptions.cellPadding.join('px ') + 'px;';
}
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 {
this.styleSheet.remove();
parent.appendChild(this.styleSheet);
if (!this.resultsView) {
this.resultsView = new QueryResultsView(parent, this._instantiationService, this._queryModelService);
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'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 { IQueryModelService } from '../execution/queryModel';
import QueryRunner from 'sql/parts/query/execution/queryRunner';
@@ -14,10 +14,10 @@ import { ChartTab } from './charting/chartTab';
import { QueryPlanTab } from 'sql/parts/queryPlan/queryPlan';
import * as nls from 'vs/nls';
import * as UUID from 'vs/base/common/uuid';
import { PanelViewlet } from 'vs/workbench/browser/parts/views/panelViewlet';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import * as DOM from 'vs/base/browser/dom';
import { once, anyEvent } from 'vs/base/common/event';
class ResultsView implements IPanelView {
private panelViewlet: PanelViewlet;
@@ -25,19 +25,73 @@ class ResultsView implements IPanelView {
private messagePanel: MessagePanel;
private container = document.createElement('div');
private currentDimension: DOM.Dimension;
private needsGridResize = false;
private _state: ResultsViewState;
constructor(instantiationService: IInstantiationService) {
this.panelViewlet = instantiationService.createInstance(PanelViewlet, 'resultsView', { showHeaderInTitleWhenSingleView: false });
this.gridPanel = instantiationService.createInstance(GridPanel, { title: nls.localize('gridPanel', 'Results') });
this.messagePanel = instantiationService.createInstance(MessagePanel, { title: nls.localize('messagePanel', 'Messages') });
constructor(private instantiationService: IInstantiationService) {
this.panelViewlet = this.instantiationService.createInstance(PanelViewlet, 'resultsView', { showHeaderInTitleWhenSingleView: false });
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.messagePanel.render();
this.panelViewlet.create(this.container).then(() => {
this.gridPanel.setVisible(false);
this.panelViewlet.addPanels([
{ panel: this.gridPanel, size: 1000, index: 0 },
{ panel: this.messagePanel, size: this.messagePanel.minimumSize, index: 1 }
]);
});
anyEvent(this.gridPanel.onDidChange, this.messagePanel.onDidChange)(e => {
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(this.panelViewlet.onDidSashChange)(e => {
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);
}
}
});
}
render(container: HTMLElement): void {
@@ -51,6 +105,9 @@ class ResultsView implements IPanelView {
this.gridPanel.layout(dimension.height);
}
this.currentDimension = dimension;
if (this.needsGridResize) {
this.panelViewlet.resizePanel(this.gridPanel, this.state.gridPanelSize || Math.round(this.currentDimension.height * .7));
}
}
remove(): void {
@@ -65,11 +122,21 @@ class ResultsView implements IPanelView {
public hideResultHeader() {
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 {
public readonly title = nls.localize('resultsTabTitle', 'Results');
public readonly identifier = UUID.generateUuid();
public readonly identifier = 'resultsTab';
public readonly view: ResultsView;
constructor(instantiationService: IInstantiationService) {
@@ -97,6 +164,12 @@ export class QueryResultsView {
this.chartTab = new ChartTab(instantiationService);
this._panelView = new TabbedPanel(container, { showHeaderWhenSingleView: false });
this.qpTab = new QueryPlanTab();
this._panelView.pushTab(this.resultsTab);
this._panelView.onTabChange(e => {
if (this.input) {
this.input.state.activeTab = e;
}
});
}
public style() {
@@ -104,11 +177,24 @@ export class QueryResultsView {
public set input(input: QueryResultsInput) {
this._input = input;
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;
this.resultsTab.queryRunner = queryRunner;
this.chartTab.queryRunner = queryRunner;
if (!this._panelView.contains(this.resultsTab)) {
this._panelView.pushTab(this.resultsTab);
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);
}
}
@@ -125,6 +211,7 @@ export class QueryResultsView {
}
public chartData(dataId: { resultId: number, batchId: number }): void {
this.input.state.visibleTabs.add(this.chartTab.identifier);
if (!this._panelView.contains(this.chartTab)) {
this._panelView.pushTab(this.chartTab);
}
@@ -134,6 +221,7 @@ export class QueryResultsView {
}
public showPlan(xml: string) {
this.input.state.visibleTabs.add(this.qpTab.identifier);
if (!this._panelView.contains(this.qpTab)) {
this._panelView.pushTab(this.qpTab);
}

View File

@@ -3,6 +3,7 @@
* 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 { Builder, $ } from 'vs/base/browser/builder';
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 { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachEditableDropdownStyler, attachSelectBoxStyler } from 'sql/common/theme/styler';
import { ISelectionData } from 'sqlops';
import {
@@ -25,6 +27,8 @@ import { QueryEditor } from 'sql/parts/query/editor/queryEditor';
import { IQueryModelService } from 'sql/parts/query/execution/queryModel';
import { INotificationService } from 'vs/platform/notification/common/notification';
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
@@ -431,6 +435,9 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
private _isConnected: boolean;
private $databaseListDropdown: Builder;
private _dropdown: Dropdown;
private _databaseSelectBox: SelectBox;
private _isInAccessibilityMode: boolean;
private readonly _selectDatabaseString: string = nls.localize("selectDatabase", "Select Database");
// CONSTRUCTOR /////////////////////////////////////////////////////////
constructor(
@@ -439,23 +446,33 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@INotificationService private _notificationService: INotificationService,
@IContextViewService contextViewProvider: IContextViewService,
@IThemeService themeService: IThemeService
@IThemeService themeService: IThemeService,
@IConfigurationService private readonly _configurationService: IConfigurationService
) {
super();
this._toDispose = [];
this.$databaseListDropdown = $('.databaseListDropdown');
let selectString = nls.localize("selectDatabase", "Select Database");
this._dropdown = new Dropdown(this.$databaseListDropdown.getHTMLElement(), contextViewProvider, themeService, {
strictSelection: true,
placeholder: selectString,
ariaLabel: selectString,
actionLabel: nls.localize('listDatabases.toggleDatabaseNameDropdown', 'Select Database Toggle Dropdown')
});
this._dropdown.onValueChange(s => this.databaseSelected(s));
this._isInAccessibilityMode = this._configurationService.getValue('editor.accessibilitySupport') === 'on';
if (this._isInAccessibilityMode) {
this._databaseSelectBox = new SelectBox([this._selectDatabaseString], this._selectDatabaseString, contextViewProvider, undefined, { ariaLabel: this._selectDatabaseString });
this._databaseSelectBox.render(this.$databaseListDropdown.getHTMLElement());
this._databaseSelectBox.onDidSelect(e => { this.databaseSelected(e.selected); });
this._databaseSelectBox.disable();
} 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
let self = this;
this._toDispose.push(this._dropdown.onFocus(() => { self.onDropdownFocus(); }));
this._toDispose.push(this._connectionManagementService.onConnectionChanged(params => { self.onConnectionChanged(params); }));
}
@@ -465,7 +482,12 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
}
public style(styles) {
this._dropdown.style(styles);
if (this._isInAccessibilityMode) {
this._databaseSelectBox.style(styles);
}
else {
this._dropdown.style(styles);
}
}
public setActionContext(context: any): void {
@@ -477,11 +499,27 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
}
public focus(): void {
this._dropdown.focus();
if (this._isInAccessibilityMode) {
this._databaseSelectBox.focus();
} else {
this._dropdown.focus();
}
}
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 {
@@ -496,9 +534,15 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
public onDisconnect(): void {
this._isConnected = false;
this._dropdown.enabled = false;
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 /////////////////////////////////////////////////////
@@ -515,22 +559,22 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
this._connectionManagementService.changeDatabase(this._editor.uri, dbName)
.then(
result => {
if (!result) {
result => {
if (!result) {
this.resetDatabaseName();
this._notificationService.notify({
severity: Severity.Error,
message: nls.localize('changeDatabase.failed', "Failed to change database")
});
}
},
error => {
this.resetDatabaseName();
this._notificationService.notify({
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() {
@@ -545,7 +589,11 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
}
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 {
@@ -579,9 +627,26 @@ export class ListDatabasesActionItem extends EventEmitter implements IActionItem
private updateConnection(databaseName: string) {
this._isConnected = true;
this._dropdown.enabled = true;
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 //////////////////////////////////////////////////

View File

@@ -12,7 +12,7 @@ import * as WorkbenchUtils from 'sql/workbench/common/sqlWorkbenchUtils';
import { IQueryManagementService } from 'sql/parts/query/common/queryManagement';
import * as Utils from 'sql/parts/connection/common/utils';
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 { 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 { IDisposable } from 'vs/base/common/lifecycle';
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 { ResultSerializer } from 'sql/parts/query/common/resultSerializer';
import { TPromise } from 'vs/base/common/winjs.base';
export interface IEditSessionReadyEvent {
ownerUri: string;
@@ -73,25 +74,27 @@ export default class QueryRunner {
public get isQueryPlan(): boolean { return this._isQueryPlan; }
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
if (types.isUndefinedOrNull(l)) {
return [e];
} else {
return l.concat(e);
}
}));
});
private _echoedMessages = echo(this._debouncedMessage.event);
public readonly onMessage = this._echoedMessages.event;
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
if (types.isUndefinedOrNull(l)) {
return [e];
} else {
return l.concat(e);
}
}));
});
private _echoedResultSet = echo(this._debouncedResultSet.event);
public readonly onResultSet = this._echoedResultSet.event;
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: sqlops.ISelectionData, 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._echoedResultSet.clear();
this._debouncedMessage.clear();
this._debouncedResultSet.clear();
let ownerUri = this.uri;
this._batchSets = [];
this._hasCompleted = false;
@@ -242,16 +250,18 @@ export default class QueryRunner {
}
});
this._eventEmitter.emit(EventType.COMPLETE, Utils.parseNumAsTimeString(this._totalElapsedMilliseconds));
let timeStamp = Utils.parseNumAsTimeString(this._totalElapsedMilliseconds);
this._eventEmitter.emit(EventType.COMPLETE, timeStamp);
// We're done with this query so shut down any waiting mechanisms
let message = {
message: nls.localize('query.message.executionTime', 'Total execution time: {0}', this._totalElapsedMilliseconds),
message: nls.localize('query.message.executionTime', 'Total execution time: {0}', timeStamp),
isError: false,
time: undefined
};
this._onQueryEnd.fire(Utils.parseNumAsTimeString(this._totalElapsedMilliseconds));
this._onQueryEnd.fire(timeStamp);
this._onMessage.fire(message);
}
@@ -274,7 +284,8 @@ export default class QueryRunner {
this.batchSets[batch.id] = batch;
let message = {
message: nls.localize('query.message.startQuery', 'Started executing query at Line {0}', batch.selection.startLine),
// account for index by 1
message: nls.localize('query.message.startQuery', 'Started executing query at Line {0}', batch.selection.startLine + 1),
time: new Date(batch.executionStart).toLocaleTimeString(),
selection: batch.selection,
isError: false

View File

@@ -22,6 +22,7 @@ import { PanelComponent, IPanelOptions } from 'sql/base/browser/ui/panel/panel.c
import * as nls from 'vs/nls';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export const QUERY_OUTPUT_SELECTOR: string = 'query-output-component';
@@ -66,7 +67,8 @@ export class QueryOutputComponent implements OnDestroy {
constructor(
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef,
@Inject(IBootstrapParams) public queryParameters: IQueryComponentParams
@Inject(IBootstrapParams) public queryParameters: IQueryComponentParams,
@Inject(IConfigurationService) private _configurationService: IConfigurationService
) {
}
@@ -75,12 +77,14 @@ export class QueryOutputComponent implements OnDestroy {
*/
public ngAfterViewInit(): void {
this._disposables.push(toDisposableSubscription(this.queryComponent.queryPlanAvailable.subscribe((xml) => {
this.hasQueryPlan = true;
this._cd.detectChanges();
this._panel.selectTab(this.topOperationsTabIdentifier);
this.topOperationsComponent.planXml = xml;
this._panel.selectTab(this.queryPlanTabIdentifier);
this.queryPlanComponent.planXml = xml;
if (this._configurationService.getValue('workbench')['enablePreviewFeatures']) {
this.hasQueryPlan = true;
this._cd.detectChanges();
this._panel.selectTab(this.topOperationsTabIdentifier);
this.topOperationsComponent.planXml = xml;
this._panel.selectTab(this.queryPlanTabIdentifier);
this.queryPlanComponent.planXml = xml;
}
})));
this._disposables.push(toDisposableSubscription(this.queryComponent.showChartRequested.subscribe((dataSet) => {

View File

@@ -13,9 +13,13 @@ import { localize } from 'vs/nls';
import * as UUID from 'vs/base/common/uuid';
import { Builder } from 'vs/base/browser/builder';
export class QueryPlanState {
xml: string;
}
export class QueryPlanTab implements IPanelTab {
public readonly title = localize('queryPlanTitle', 'Query Plan');
public readonly identifier = UUID.generateUuid();
public readonly identifier = 'QueryPlanTab';
public readonly view: QueryPlanView;
constructor() {
@@ -27,6 +31,7 @@ export class QueryPlanView implements IPanelView {
private qp: QueryPlan;
private xml: string;
private container = document.createElement('div');
private _state: QueryPlanState;
public render(container: HTMLElement): void {
if (!this.qp) {
@@ -47,6 +52,20 @@ export class QueryPlanView implements IPanelView {
} else {
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;
}
}

View File

@@ -93,7 +93,7 @@ const viewletDescriptor = new ViewletDescriptor(
VIEWLET_ID,
'Task History',
'taskHistoryViewlet',
-90
1
);
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);

Some files were not shown because too many files have changed in this diff Show More