Compare commits

...

27 Commits

Author SHA1 Message Date
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
80 changed files with 1128 additions and 276 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,6 +1,6 @@
{
"name": "sqlops",
"version": "0.33.1",
"version": "0.33.2",
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
"author": {
"name": "Microsoft Corporation"

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([{

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

@@ -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

@@ -0,0 +1,142 @@
import { mixin } from 'vs/base/common/objects';
require.__$__nodeRequire('slickgrid/plugins/slick.cellrangedecorator');
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) {
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.focus();
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();
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,10 @@
import { mixin } from 'vs/base/common/objects';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { CellRangeSelector, ICellRangeSelector } from 'sql/base/browser/ui/table/plugins/cellRangeSelector';
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>;
}
export interface ICellSelectionModelOptions {
cellRangeSelector?: any;
@@ -36,7 +31,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 && (<any>selectionModel).getSelectedRanges) {
ranges = (<any>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

@@ -308,10 +308,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

@@ -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) => {
@@ -193,7 +194,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,8 +219,7 @@ 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);
let AdvancedLabel = localize('advanced', 'Advanced...');

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

@@ -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

@@ -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

@@ -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

@@ -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;
@@ -153,7 +154,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;
}

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

@@ -27,8 +27,9 @@ 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

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

@@ -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

@@ -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

@@ -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,13 @@
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%;
}

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

@@ -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

@@ -34,6 +34,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 +59,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 +87,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);
}
}

View File

@@ -38,6 +38,7 @@ 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 { CopyKeybind } from 'sql/base/browser/ui/table/plugins/copyKeybind.plugin';
const ROW_HEIGHT = 29;
const HEADER_HEIGHT = 26;
@@ -215,10 +216,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;
@@ -295,11 +292,30 @@ 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({
selection: e,
batchId: this.resultSet.batchId,
resultId: this.resultSet.id,
cell: this.table.grid.getActiveCell(),
runner: this.runner,
table: this.table,
tableState: this.state
});
});
this.columns.unshift(numberColumn.getColumnDefinition());
this.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._register(this.table.onContextMenu(this.contextMenu, this));
this._register(this.table.onClick(this.onTableClick, this));

View File

@@ -44,6 +44,7 @@ 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 +97,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 +295,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 +448,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 +472,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);
}
@@ -537,8 +556,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 +570,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 +602,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 +610,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

@@ -18,6 +18,7 @@ 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 } from 'vs/base/common/event';
class ResultsView implements IPanelView {
private panelViewlet: PanelViewlet;
@@ -38,6 +39,13 @@ class ResultsView implements IPanelView {
{ panel: this.messagePanel, size: this.messagePanel.minimumSize, index: 1 }
]);
});
let gridResizeList = this.gridPanel.onDidChange(e => {
this.panelViewlet.resizePanel(this.gridPanel, this.gridPanel.maximumSize);
});
// once the user changes the sash we should stop trying to resize the grid
once(this.panelViewlet.onDidSashChange)(e => {
gridResizeList.dispose();
});
}
render(container: HTMLElement): void {

View File

@@ -242,16 +242,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 +276,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) => {

57
src/sql/sqlops.d.ts vendored
View File

@@ -209,6 +209,38 @@ declare module 'sqlops' {
id: string;
}
/**
* Options for the actions that could happen after connecting is complete
*/
export interface IConnectionCompletionOptions {
/**
* Save the connection to MRU and settings (only save to setting if profile.saveProfile is set to true)
* Default is true.
*/
saveConnection: boolean;
/**
* If true, open the dashboard after connection is complete.
* If undefined / false, dashboard won't be opened after connection completes.
* Default is false.
*/
showDashboard?: boolean;
/**
* If undefined / true, open the connection dialog if connection fails.
* If false, connection dialog won't be opened even if connection fails.
* Default is true.
*/
showConnectionDialogOnError?: boolean;
/**
* If undefined / true, open the connection firewall rule dialog if connection fails.
* If false, connection firewall rule dialog won't be opened even if connection fails.
* Default is true.
*/
showFirewallRuleOnError?: boolean;
}
export interface ConnectionInfoSummary {
/**
@@ -1855,14 +1887,19 @@ declare module 'sqlops' {
* Gets all added accounts.
* @returns {Thenable<Account>} Promise to return the accounts
*/
export function getAllAccounts(): Thenable<AccountWithProviderHandle[]>;
export function getAllAccounts(): Thenable<Account[]>;
/**
* Generates a security token by asking the account's provider
* @param {Account} account Account to generate security token for
* @return {Thenable<{}>} Promise to return the security token
*/
export function getSecurityToken(account: AccountWithProviderHandle): Thenable<{}>;
export function getSecurityToken(account: Account): Thenable<{}>;
/**
* An [event](#Event) which fires when the accounts have changed.
*/
export const onDidChangeAccounts: vscode.Event<DidChangeAccountsParams>;
}
/**
@@ -1930,19 +1967,9 @@ declare module 'sqlops' {
isStale: boolean;
}
/**
* Represents an account with account provider's handle
*/
export interface AccountWithProviderHandle {
/**
* Account
*/
account: Account;
/**
* Account's provider handle
*/
providerHandle: number;
export interface DidChangeAccountsParams {
// Updated accounts
accounts: Account[];
}
// - ACCOUNT PROVIDER //////////////////////////////////////////////////

View File

@@ -147,6 +147,15 @@ declare module 'sqlops' {
*/
updateProperties(properties: { [key: string]: any }): Thenable<void>;
/**
* Sends an updated property of the component to the UI
*
* @returns {Thenable<void>} Thenable that completes once the update
* has been applied in the UI
* @memberof Component
*/
updateProperty(key: string, value: any): Thenable<void>;
enabled: boolean;
/**
* Event fired to notify that the component's validity has changed
@@ -312,7 +321,7 @@ declare module 'sqlops' {
/**
* Matches the CSS style key and its available values.
*/
CSSStyles?: { [key: string]: string }
CSSStyles?: { [key: string]: string };
}
export interface FormItemLayout {
@@ -427,6 +436,10 @@ declare module 'sqlops' {
* Without this the component will fail to correctly size itself
*/
position?: string;
/**
* Matches the CSS style key and its available values.
*/
CSSStyles?: { [key: string]: string };
}
export interface ComponentWithIcon {
@@ -1246,6 +1259,6 @@ declare module 'sqlops' {
* returns the connection otherwise returns undefined
* @param callback
*/
export function openConnectionDialog(provider?: string[], initialConnectionProfile?: IConnectionProfile): Thenable<connection.Connection>;
export function openConnectionDialog(providers?: string[], initialConnectionProfile?: IConnectionProfile, connectionCompletionOptions?: IConnectionCompletionOptions): Thenable<connection.Connection>;
}
}

View File

@@ -14,11 +14,14 @@ import {
SqlMainContext,
} from 'sql/workbench/api/node/sqlExtHost.protocol';
import { IMainContext } from 'vs/workbench/api/node/extHost.protocol';
import { Event, Emitter } from 'vs/base/common/event';
export class ExtHostAccountManagement extends ExtHostAccountManagementShape {
private _handlePool: number = 0;
private _proxy: MainThreadAccountManagementShape;
private _providers: { [handle: number]: AccountProviderWithMetadata } = {};
private _accounts: { [handle: number]: sqlops.Account[] } = {};
private readonly _onDidChangeAccounts = new Emitter<sqlops.DidChangeAccountsParams>();
constructor(mainContext: IMainContext) {
super();
@@ -31,10 +34,6 @@ export class ExtHostAccountManagement extends ExtHostAccountManagementShape {
return this._withProvider(handle, (provider: sqlops.AccountProvider) => provider.clear(accountKey));
}
public $getSecurityToken(handle: number, account: sqlops.Account): Thenable<{}> {
return this._withProvider(handle, (provider: sqlops.AccountProvider) => provider.getSecurityToken(account));
}
public $initialize(handle: number, restoredAccounts: sqlops.Account[]): Thenable<sqlops.Account[]> {
return this._withProvider(handle, (provider: sqlops.AccountProvider) => provider.initialize(restoredAccounts));
}
@@ -64,31 +63,49 @@ export class ExtHostAccountManagement extends ExtHostAccountManagementShape {
this._proxy.$accountUpdated(updatedAccount);
}
public $getAllAccounts(): Thenable<sqlops.AccountWithProviderHandle[]> {
public $getAllAccounts(): Thenable<sqlops.Account[]> {
if (Object.keys(this._providers).length === 0) {
throw new Error('No account providers registered.');
}
let accountWithProviderHandles: sqlops.AccountWithProviderHandle[] = [];
let promises: Thenable<void>[] = [];
this._accounts = {};
for (let providerKey in this._providers) {
let providerHandle = parseInt(providerKey);
let provider = this._providers[providerHandle];
const resultAccounts: sqlops.Account[] = [];
const promises: Thenable<void>[] = [];
for (const providerKey in this._providers) {
const providerHandle = parseInt(providerKey);
const provider = this._providers[providerHandle];
promises.push(this._proxy.$getAccountsForProvider(provider.metadata.id).then(
(accounts) => {
accounts.forEach((account) => {
accountWithProviderHandles.push({
account: account,
providerHandle: providerHandle
});
});
this._accounts[providerHandle] = accounts;
resultAccounts.push(...accounts);
}
));
}
return Promise.all(promises).then(() => accountWithProviderHandles);
return Promise.all(promises).then(() => resultAccounts);
}
public $getSecurityToken(account: sqlops.Account): Thenable<{}> {
for (const handle in this._accounts) {
const providerHandle = parseInt(handle);
if (this._accounts[handle].findIndex((acct) => acct.key.accountId === account.key.accountId) !== -1) {
return this._withProvider(providerHandle, (provider: sqlops.AccountProvider) => provider.getSecurityToken(account));
}
}
throw new Error(`Account ${account.key.accountId} not found.`);
}
public get onDidChangeAccounts(): Event<sqlops.DidChangeAccountsParams> {
return this._onDidChangeAccounts.event;
}
public $accountsChanged(handle: number, accounts: sqlops.Account[]): Thenable<void> {
return this._onDidChangeAccounts.fire({ accounts: accounts });
}
public $registerAccountProvider(providerMetadata: sqlops.AccountProviderMetadata, provider: sqlops.AccountProvider): Disposable {

View File

@@ -32,8 +32,8 @@ export class ExtHostConnectionManagement extends ExtHostConnectionManagementShap
return this._proxy.$getCredentials(connectionId);
}
public $openConnectionDialog(providers?: string[], initialConnectionProfile?: sqlops.IConnectionProfile): Thenable<sqlops.connection.Connection> {
return this._proxy.$openConnectionDialog(providers, initialConnectionProfile);
public $openConnectionDialog(providers?: string[], initialConnectionProfile?: sqlops.IConnectionProfile, connectionCompletionOptions?: sqlops.IConnectionCompletionOptions): Thenable<sqlops.connection.Connection> {
return this._proxy.$openConnectionDialog(providers, initialConnectionProfile, connectionCompletionOptions);
}
public $listDatabases(connectionId: string): Thenable<string[]> {

View File

@@ -340,7 +340,7 @@ class FormContainerBuilder extends ContainerBuilderImpl<sqlops.FormContainer, sq
itemConfig.config.isInGroup = true;
this._component.insertItem(component.component as ComponentWrapper, componentIndex, itemConfig.config);
if (componentIndex) {
componentIndex ++;
componentIndex++;
}
this.addComponentActions(component, layout);
});
@@ -548,7 +548,7 @@ class ComponentWrapper implements sqlops.Component {
} else {
throw new Error(nls.localize('invalidIndex', 'The index is invalid.'));
}
this._proxy.$addToContainer(this._handle, this.id, config.toIItemConfig(), index).then(undefined, this.handleError);
this._proxy.$addToContainer(this._handle, this.id, config.toIItemConfig(), index).then(undefined, (err) => this.handleError(err));
}
public setLayout(layout: any): Thenable<void> {
@@ -560,6 +560,10 @@ class ComponentWrapper implements sqlops.Component {
return this.notifyPropertyChanged();
}
public updateProperty(key: string, value: any): Thenable<void> {
return this.setProperty(key, value);
}
protected notifyPropertyChanged(): Thenable<void> {
return this._proxy.$setProperties(this._handle, this._id, this.properties);
}

View File

@@ -16,6 +16,7 @@ import {
} from 'sql/workbench/api/node/sqlExtHost.protocol';
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
import { UpdateAccountListEventParams } from 'sql/services/accountManagement/eventTypes';
@extHostNamedCustomer(SqlMainContext.MainThreadAccountManagement)
export class MainThreadAccountManagement implements MainThreadAccountManagementShape {
@@ -32,6 +33,20 @@ export class MainThreadAccountManagement implements MainThreadAccountManagementS
this._proxy = extHostContext.getProxy(SqlExtHostContext.ExtHostAccountManagement);
}
this._toDispose = [];
this._accountManagementService.updateAccountListEvent((e: UpdateAccountListEventParams) => {
if (!e) {
return;
}
const providerMetadataIndex = Object.values(this._providerMetadata).findIndex((providerMetadata: sqlops.AccountProviderMetadata) => providerMetadata.id === e.providerId);
if (providerMetadataIndex === -1) {
return;
}
const providerHandle = parseInt(Object.keys(this._providerMetadata)[providerMetadataIndex]);
this._proxy.$accountsChanged(providerHandle, e.accountList);
});
}
public $beginAutoOAuthDeviceCode(providerId: string, title: string, message: string, userCode: string, uri: string): Thenable<void> {
@@ -62,7 +77,7 @@ export class MainThreadAccountManagement implements MainThreadAccountManagementS
return self._proxy.$clear(handle, accountKey);
},
getSecurityToken(account: sqlops.Account): Thenable<{}> {
return self._proxy.$getSecurityToken(handle, account);
return self._proxy.$getSecurityToken(account);
},
initialize(restoredAccounts: sqlops.Account[]): Thenable<sqlops.Account[]> {
return self._proxy.$initialize(handle, restoredAccounts);

View File

@@ -14,6 +14,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { isUndefinedOrNull } from 'vs/base/common/types';
@extHostNamedCustomer(SqlMainContext.MainThreadConnectionManagement)
export class MainThreadConnectionManagement implements MainThreadConnectionManagementShape {
@@ -51,13 +52,27 @@ export class MainThreadConnectionManagement implements MainThreadConnectionManag
}
public async $openConnectionDialog(providers: string[], initialConnectionProfile?: IConnectionProfile): Promise<sqlops.connection.Connection> {
public async $openConnectionDialog(providers: string[], initialConnectionProfile?: IConnectionProfile, connectionCompletionOptions?: sqlops.IConnectionCompletionOptions): Promise<sqlops.connection.Connection> {
let connectionProfile = await this._connectionDialogService.openDialogAndWait(this._connectionManagementService, { connectionType: 1, providers: providers }, initialConnectionProfile);
return connectionProfile ? {
const connection = connectionProfile ? {
connectionId: connectionProfile.id,
options: connectionProfile.options,
providerName: connectionProfile.providerName
} : undefined;
if (connectionCompletionOptions) {
// Somehow, connectionProfile.saveProfile is false even if initialConnectionProfile.saveProfile is true, reset the flag here.
connectionProfile.saveProfile = initialConnectionProfile.saveProfile;
await this._connectionManagementService.connectAndSaveProfile(connectionProfile, undefined, {
saveTheConnection: isUndefinedOrNull(connectionCompletionOptions.saveConnection) ? true : connectionCompletionOptions.saveConnection,
showDashboard: isUndefinedOrNull(connectionCompletionOptions.showDashboard) ? false : connectionCompletionOptions.showDashboard,
params: undefined,
showConnectionDialogOnError: isUndefinedOrNull(connectionCompletionOptions.showConnectionDialogOnError) ? true : connectionCompletionOptions.showConnectionDialogOnError,
showFirewallRuleOnError: isUndefinedOrNull(connectionCompletionOptions.showFirewallRuleOnError) ? true : connectionCompletionOptions.showFirewallRuleOnError
});
}
return connection;
}
public async $listDatabases(connectionId: string): Promise<string[]> {

View File

@@ -12,6 +12,7 @@ import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionS
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { realpath } from 'fs';
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
import URI from 'vs/base/common/uri';
import * as sqlops from 'sqlops';
import * as vscode from 'vscode';
@@ -91,11 +92,14 @@ export function createApiFactory(
accountUpdated(updatedAccount: sqlops.Account): void {
return extHostAccountManagement.$accountUpdated(updatedAccount);
},
getAllAccounts(): Thenable<sqlops.AccountWithProviderHandle[]> {
getAllAccounts(): Thenable<sqlops.Account[]> {
return extHostAccountManagement.$getAllAccounts();
},
getSecurityToken(account: sqlops.AccountWithProviderHandle): Thenable<{}> {
return extHostAccountManagement.$getSecurityToken(account.providerHandle, account.account);
getSecurityToken(account: sqlops.Account): Thenable<{}> {
return extHostAccountManagement.$getSecurityToken(account);
},
onDidChangeAccounts(listener: (e: sqlops.DidChangeAccountsParams) => void, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
return extHostAccountManagement.onDidChangeAccounts(listener, thisArgs, disposables);
}
};
@@ -110,8 +114,8 @@ export function createApiFactory(
getCredentials(connectionId: string): Thenable<{ [name: string]: string }> {
return extHostConnectionManagement.$getCredentials(connectionId);
},
openConnectionDialog(providers?: string[], initialConnectionProfile?: sqlops.IConnectionProfile): Thenable<sqlops.connection.Connection> {
return extHostConnectionManagement.$openConnectionDialog(providers, initialConnectionProfile);
openConnectionDialog(providers?: string[], initialConnectionProfile?: sqlops.IConnectionProfile, connectionCompletionOptions?: sqlops.IConnectionCompletionOptions): Thenable<sqlops.connection.Connection> {
return extHostConnectionManagement.$openConnectionDialog(providers, initialConnectionProfile, connectionCompletionOptions);
},
listDatabases(connectionId: string): Thenable<string[]> {
return extHostConnectionManagement.$listDatabases(connectionId);
@@ -482,7 +486,7 @@ function defineAPI(factory: ISqlExtensionApiFactory, extensionPaths: TrieMap<IEx
setDefaultApiImpl: (defaultImpl: ApiImpl) => void,
parent: any): ApiImpl {
// get extension id from filename and api for extension
const ext = extensionPaths.findSubstr(parent.filename);
const ext = extensionPaths.findSubstr(URI.file(parent.filename).fsPath);
if (ext) {
let apiImpl = apiMap.get(ext.id);
if (!apiImpl) {
@@ -494,6 +498,7 @@ function defineAPI(factory: ISqlExtensionApiFactory, extensionPaths: TrieMap<IEx
// fall back to a default implementation
if (!defaultImpl) {
console.warn(`Could not identify extension for 'vscode' require call from ${parent.filename}`);
defaultImpl = createApi(nullExtensionDescription);
setDefaultApiImpl(defaultImpl);
}

View File

@@ -27,10 +27,11 @@ import {
export abstract class ExtHostAccountManagementShape {
$autoOAuthCancelled(handle: number): Thenable<void> { throw ni(); }
$clear(handle: number, accountKey: sqlops.AccountKey): Thenable<void> { throw ni(); }
$getSecurityToken(handle: number, account: sqlops.Account): Thenable<{}> { throw ni(); }
$getSecurityToken(account: sqlops.Account): Thenable<{}> { throw ni(); }
$initialize(handle: number, restoredAccounts: sqlops.Account[]): Thenable<sqlops.Account[]> { throw ni(); }
$prompt(handle: number): Thenable<sqlops.Account> { throw ni(); }
$refresh(handle: number, account: sqlops.Account): Thenable<sqlops.Account> { throw ni(); }
$accountsChanged(handle: number, accounts: sqlops.Account[]): Thenable<void> { throw ni(); }
}
export abstract class ExtHostConnectionManagementShape {
@@ -502,7 +503,7 @@ export interface MainThreadConnectionManagementShape extends IDisposable {
$getActiveConnections(): Thenable<sqlops.connection.Connection[]>;
$getCurrentConnection(): Thenable<sqlops.connection.Connection>;
$getCredentials(connectionId: string): Thenable<{ [name: string]: string }>;
$openConnectionDialog(providers: string[], initialConnectionProfile?: sqlops.IConnectionProfile): Thenable<sqlops.connection.Connection>;
$openConnectionDialog(providers: string[], initialConnectionProfile?: sqlops.IConnectionProfile, connectionCompletionOptions?: sqlops.IConnectionCompletionOptions): Thenable<sqlops.connection.Connection>;
$listDatabases(connectionId: string): Thenable<string[]>;
$getConnectionString(connectionId: string, includePassword: boolean): Thenable<string>;
$getUriForConnection(connectionId: string): Thenable<string>;

View File

@@ -14,6 +14,7 @@ import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/wor
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { ShowCurrentReleaseNotesAction } from 'sql/workbench/update/releaseNotes';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IConfigurationRegistry, Extensions as ConfigExtensions } from 'vs/platform/configuration/common/configurationRegistry';
new Actions.BackupAction().registerTask(false);
new Actions.RestoreAction().registerTask(false);
@@ -23,3 +24,16 @@ new Actions.ConfigureDashboardAction().registerTask();
// add product update and release notes contributions
Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions)
.registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), 'Show Getting Started');
Registry.as<IConfigurationRegistry>(ConfigExtensions.Configuration).registerConfiguration({
'id': 'previewFeatures',
'title': nls.localize('previewFeatures.configTitle', 'Preview Features'),
'type': 'object',
'properties': {
'workbench.enablePreviewFeatures': {
'type': 'boolean',
'default': undefined,
'description': nls.localize('previewFeatures.configEnable', 'Enable unreleased preview features')
}
}
});

View File

@@ -27,6 +27,8 @@ import { IWindowsService } from 'vs/platform/windows/common/windows';
import * as nls from 'vs/nls';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import { INotificationService } from 'vs/platform/notification/common/notification';
export interface BaseActionContext {
object?: ObjectMetadata;
@@ -300,6 +302,14 @@ export class BackupAction extends Task {
}
runTask(accessor: ServicesAccessor, profile: IConnectionProfile): TPromise<void> {
let configurationService = accessor.get<IWorkspaceConfigurationService>(IWorkspaceConfigurationService);
let previewFeaturesEnabled: boolean = configurationService.getValue('workbench')['enablePreviewFeatures'];
if (!previewFeaturesEnabled) {
return new TPromise<void>((resolve, reject) => {
accessor.get<INotificationService>(INotificationService).info(nls.localize('backup.isPreviewFeature', 'You must enable preview features in order to use backup'));
});
}
return new TPromise<void>((resolve, reject) => {
TaskUtilities.showBackup(
profile,
@@ -331,6 +341,14 @@ export class RestoreAction extends Task {
}
runTask(accessor: ServicesAccessor, profile: IConnectionProfile): TPromise<void> {
let configurationService = accessor.get<IWorkspaceConfigurationService>(IWorkspaceConfigurationService);
let previewFeaturesEnabled: boolean = configurationService.getValue('workbench')['enablePreviewFeatures'];
if (!previewFeaturesEnabled) {
return new TPromise<void>((resolve, reject) => {
accessor.get<INotificationService>(INotificationService).info(nls.localize('restore.isPreviewFeature', 'You must enable preview features in order to use restore'));
});
}
return new TPromise<void>((resolve, reject) => {
TaskUtilities.showRestore(
profile,

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TPromise } from 'vs/base/common/winjs.base';
import { Event } from 'vs/base/common/event';
import { ITreeViewDataProvider, ITreeItem } from 'vs/workbench/common/views';
export interface ITreeComponentItem extends ITreeItem {
@@ -16,7 +14,3 @@ export interface ITreeComponentItem extends ITreeItem {
export interface IModelViewTreeViewDataProvider extends ITreeViewDataProvider {
refresh(itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeComponentItem });
}
export interface IModelViewTreeViewDataProvider {
getChildren(element?: ITreeComponentItem): TPromise<ITreeComponentItem[]>;
}

View File

@@ -0,0 +1,70 @@
/*---------------------------------------------------------------------------------------------
* 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 { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { localize } from 'vs/nls';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export class EnablePreviewFeatures implements IWorkbenchContribution {
private static ENABLE_PREVIEW_FEATURES_SHOWN = 'workbench.enablePreviewFeaturesShown';
constructor(
@IStorageService storageService: IStorageService,
@IOpenerService openerService: IOpenerService,
@INotificationService notificationService: INotificationService,
@IWindowService windowService: IWindowService,
@IWindowsService windowsService: IWindowsService,
@ITelemetryService telemetryService: ITelemetryService,
@IConfigurationService configurationService: IConfigurationService
) {
let previewFeaturesEnabled = configurationService.getValue('workbench')['enablePreviewFeatures'];
if (previewFeaturesEnabled || storageService.get(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN)) {
return;
}
Promise.all([
windowService.isFocused(),
windowsService.getWindowCount()
]).then(([focused, count]) => {
if (!focused && count > 1) {
return null;
}
configurationService.updateValue('workbench.enablePreviewFeatures', false);
const enablePreviewFeaturesNotice = localize('enablePreviewFeatures.notice', "Would you like to enable preview features?");
notificationService.prompt(
Severity.Info,
enablePreviewFeaturesNotice,
[{
label: localize('enablePreviewFeatures.yes', "Yes"),
run: () => {
configurationService.updateValue('workbench.enablePreviewFeatures', true);
storageService.store(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true);
}
}, {
label: localize('enablePreviewFeatures.no', "No"),
run: () => {
configurationService.updateValue('workbench.enablePreviewFeatures', false);
}
}, {
label: localize('enablePreviewFeatures.never', "No, don't show again"),
run: () => {
configurationService.updateValue('workbench.enablePreviewFeatures', false);
storageService.store(EnablePreviewFeatures.ENABLE_PREVIEW_FEATURES_SHOWN, true);
},
isSecondary: true
}]
);
})
.then(null, onUnexpectedError);
}
}

View File

@@ -16,7 +16,7 @@ class TestComponent extends ComponentBase {
public descriptor: IComponentDescriptor;
constructor(public modelStore: IModelStore, id: string) {
super(undefined);
super(undefined, undefined);
this.descriptor = modelStore.createComponentDescriptor('TestComponent', id);
this.baseInit();
}
@@ -33,7 +33,7 @@ class TestContainer extends ContainerBase<TestComponent> {
public descriptor: IComponentDescriptor;
constructor(public modelStore: IModelStore, id: string) {
super(undefined);
super(undefined, undefined);
this.descriptor = modelStore.createComponentDescriptor('TestContainer', id);
this._changeRef = {
detectChanges: () => undefined

View File

@@ -6,7 +6,6 @@
'use strict';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { EditorInput } from 'vs/workbench/common/editor';
import { IEditorDescriptor } from 'vs/workbench/browser/editor';
import { TPromise } from 'vs/base/common/winjs.base';
import URI from 'vs/base/common/uri';
@@ -30,8 +29,9 @@ import * as TypeMoq from 'typemoq';
import * as assert from 'assert';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { INotification, INotificationService } from 'vs/platform/notification/common/notification';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
suite('SQL QueryEditor Tests', () => {
let queryModelService: QueryModelService;
@@ -40,6 +40,7 @@ suite('SQL QueryEditor Tests', () => {
let notificationService: TypeMoq.Mock<INotificationService>;
let editorDescriptorService: TypeMoq.Mock<EditorDescriptorService>;
let connectionManagementService: TypeMoq.Mock<ConnectionManagementService>;
let configurationService: TypeMoq.Mock<ConfigurationService>;
let memento: TypeMoq.Mock<Memento>;
let queryInput: QueryInput;
@@ -57,7 +58,8 @@ suite('SQL QueryEditor Tests', () => {
undefined,
editorDescriptorService.object,
undefined,
undefined);
undefined,
configurationService.object);
};
setup(() => {
@@ -134,6 +136,14 @@ suite('SQL QueryEditor Tests', () => {
// Create a QueryModelService
queryModelService = new QueryModelService(instantiationService.object, notificationService.object);
configurationService = TypeMoq.Mock.ofInstance({
getValue: () => undefined,
onDidChangeConfiguration: () => undefined
} as any);
configurationService.setup(x => x.getValue(TypeMoq.It.isAny())).returns(() => {
return { enablePreviewFeatures: true };
});
});
test('createEditor creates only the taskbar', (done) => {

View File

@@ -292,16 +292,7 @@ suite('ExtHostAccountManagement', () => {
};
let mockAccounts = [mockAccount1, mockAccount2];
let expectedAccounts = [
{
account: mockAccount1,
providerHandle: 0
},
{
account: mockAccount2,
providerHandle: 0
}
];
let expectedAccounts = [mockAccount1, mockAccount2];
let mockAccountManagementService = getMockAccountManagementService(mockAccounts);
instantiationService.stub(IAccountManagementService, mockAccountManagementService.object);
@@ -341,6 +332,110 @@ suite('ExtHostAccountManagement', () => {
});
done();
});
test('GetSecurityToken - Success', (done) => {
let mockAccountProviderMetadata = {
id: 'azure',
displayName: 'Azure'
};
let mockAccount1 = {
key: {
providerId: mockAccountProviderMetadata.id,
accountId: 'azure_account_1'
},
displayInfo: {
contextualDisplayName: 'Microsoft Account',
accountType: 'microsoft',
displayName: 'Azure Account 1'
},
properties: [],
isStale: false
};
let mockAccounts = [mockAccount1];
let mockAccountManagementService = getMockAccountManagementService(mockAccounts);
instantiationService.stub(IAccountManagementService, mockAccountManagementService.object);
let accountManagementService = instantiationService.createInstance(MainThreadAccountManagement);
threadService.set(SqlMainContext.MainThreadAccountManagement, accountManagementService);
// Setup: Create ext host account management with registered account provider
let extHost = new ExtHostAccountManagement(threadService);
extHost.$registerAccountProvider(mockAccountProviderMetadata, new AccountProviderStub());
extHost.$getAllAccounts()
.then((accounts) => {
// If: I get security token
extHost.$getSecurityToken(mockAccount1)
.then((securityToken) => {
// Then: The call should have been passed to the account management service
mockAccountManagementService.verify(
(obj) => obj.getSecurityToken(TypeMoq.It.isAny()),
TypeMoq.Times.once()
);
}
);
}
).then(() => done(), (err) => done(err));
});
test('GetSecurityToken - Account not found', (done) => {
let mockAccountProviderMetadata = {
id: 'azure',
displayName: 'Azure'
};
let mockAccount1 = {
key: {
providerId: mockAccountProviderMetadata.id,
accountId: 'azure_account_1'
},
displayInfo: {
contextualDisplayName: 'Microsoft Account',
accountType: 'microsoft',
displayName: 'Azure Account 1'
},
properties: [],
isStale: false
};
let mockAccounts = [mockAccount1];
let mockAccountManagementService = getMockAccountManagementService(mockAccounts);
instantiationService.stub(IAccountManagementService, mockAccountManagementService.object);
let accountManagementService = instantiationService.createInstance(MainThreadAccountManagement);
threadService.set(SqlMainContext.MainThreadAccountManagement, accountManagementService);
// Setup: Create ext host account management with registered account provider
let extHost = new ExtHostAccountManagement(threadService);
extHost.$registerAccountProvider(mockAccountProviderMetadata, new AccountProviderStub());
let mockAccount2 = {
key: {
providerId: mockAccountProviderMetadata.id,
accountId: 'azure_account_2'
},
displayInfo: {
contextualDisplayName: 'Work/School Account',
accountType: 'microsoft',
displayName: 'Azure Account 2'
},
properties: [],
isStale: false
};
extHost.$getAllAccounts().then((accounts) => {
// If: I get security token for mockAccount2
// Then: It should throw
assert.throws(
() => extHost.$getSecurityToken(mockAccount2),
(error) => {
return error.message === `Account ${mockAccount2.key.accountId} not found.`;
}
);
});
done();
});
});
function getMockAccountProvider(): TypeMoq.Mock<sqlops.AccountProvider> {
@@ -362,6 +457,10 @@ function getMockAccountManagementService(accounts: sqlops.Account[]): TypeMoq.Mo
mockAccountManagementService.setup(x => x.getAccountsForProvider(TypeMoq.It.isAny()))
.returns(() => Promise.resolve(accounts));
mockAccountManagementService.setup(x => x.getSecurityToken(TypeMoq.It.isValue(accounts[0])))
.returns(() => Promise.resolve({}));
mockAccountManagementService.setup(x => x.updateAccountListEvent)
.returns(() => () => { return undefined; } );
return mockAccountManagementService;
}

View File

@@ -1252,16 +1252,21 @@ declare namespace Slick {
export interface OnDragEndEventArgs<T extends SlickData> extends GridEventArgs<T> {
// todo: need to understand $canvas drag event parameter's 'dd' object
// the documentation is not enlightening
range: { start: Slick.Cell, end: Slick.Cell };
}
export interface OnDragEventArgs<T extends SlickData> extends GridEventArgs<T> {
// todo: need to understand $canvas drag event parameter's 'dd' object
// the documentation is not enlightening
range: { start: Slick.Cell, end: Slick.Cell };
}
export interface OnDragStartEventArgs<T extends SlickData> extends GridEventArgs<T> {
// todo: need to understand $canvas drag event parameter's 'dd' object
// the documentation is not enlightening
startX: number;
startY: number;
range: { start: Slick.Cell, end: Slick.Cell };
}
export interface OnDragInitEventArgs<T extends SlickData> extends GridEventArgs<T> {

View File

@@ -24,6 +24,9 @@ import { readFile } from 'vs/base/node/pfs';
import { writeFileAndFlushSync } from 'vs/base/node/extfs';
import { generateUuid, isUUID } from 'vs/base/common/uuid';
import { values } from 'vs/base/common/map';
// {{SQL CARBON EDIT}}
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ExtensionsPolicy, ExtensionsPolicyKey } from 'vs/workbench/parts/extensions/common/extensions';
interface IRawGalleryExtensionFile {
assetType: string;
@@ -367,7 +370,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
constructor(
@IRequestService private requestService: IRequestService,
@IEnvironmentService private environmentService: IEnvironmentService,
@ITelemetryService private telemetryService: ITelemetryService
@ITelemetryService private telemetryService: ITelemetryService,
// {{SQL CARBON EDIT}}
@IConfigurationService private configurationService: IConfigurationService
) {
const config = product.extensionsGallery;
this.extensionsGalleryUrl = config && config.serviceUrl;
@@ -508,6 +513,12 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
}
let actualTotal = filteredExtensions.length;
// {{SQL CARBON EDIT}}
let extensionPolicy = this.configurationService.getValue<string>(ExtensionsPolicyKey);
if (extensionPolicy === ExtensionsPolicy.allowMicrosoft) {
filteredExtensions = filteredExtensions.filter(ext => ext.publisher && ext.publisher.displayName === 'Microsoft');
}
return { galleryExtensions: filteredExtensions, total: actualTotal };
}
@@ -551,7 +562,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
headers
}).then(context => {
if (context.res.statusCode >= 400 && context.res.statusCode < 500) {
// {{SQL CARBON EDIT}}
let extensionPolicy: string = this.configurationService.getValue<string>(ExtensionsPolicyKey);
if (context.res.statusCode >= 400 && context.res.statusCode < 500 || extensionPolicy === ExtensionsPolicy.allowNone) {
return { galleryExtensions: [], total: 0 };
}
@@ -605,7 +618,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
*/
const log = (duration: number) => this.telemetryService.publicLog('galleryService:downloadVSIX', assign(data, { duration }));
const operationParam = operation === InstallOperation.Install ? 'install' : operation === InstallOperation.Update ? 'update' : '';
// {{SQL Carbon Edit}} - Don't append install or update on to the URL
// const operationParam = operation === InstallOperation.Install ? 'install' : operation === InstallOperation.Update ? 'update' : '';
const operationParam = undefined;
const downloadAsset = operationParam ? {
uri: `${extension.assets.download.uri}&${operationParam}=true`,
fallbackUri: `${extension.assets.download.fallbackUri}?${operationParam}=true`

View File

@@ -101,6 +101,8 @@ export const AutoUpdateConfigurationKey = 'extensions.autoUpdate';
export const AutoCheckUpdatesConfigurationKey = 'extensions.autoCheckUpdates';
export const ShowRecommendationsOnlyOnDemandKey = 'extensions.showRecommendationsOnlyOnDemand';
export const CloseExtensionDetailsOnViewChangeKey = 'extensions.closeExtensionDetailsOnViewChange';
// {{SQL CARBON EDIT}}
export const ExtensionsPolicyKey = 'extensions.extensionsPolicy';
export interface IExtensionsConfiguration {
autoUpdate: boolean;
@@ -108,4 +110,13 @@ export interface IExtensionsConfiguration {
ignoreRecommendations: boolean;
showRecommendationsOnlyOnDemand: boolean;
closeExtensionDetailsOnViewChange: boolean;
// {{SQL CARBON EDIT}}
extensionsPolicy: string;
}
// {{SQL CARBON EDIT}}
export enum ExtensionsPolicy {
allowAll = 'allowAll',
allowNone = 'allowNone',
allowMicrosoft = 'allowMicrosoft'
}

View File

@@ -23,7 +23,8 @@ import { ShowRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsA
import Severity from 'vs/base/common/severity';
import { IWorkspaceContextService, IWorkspaceFolder, IWorkspace, IWorkspaceFoldersChangeEvent, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IFileService } from 'vs/platform/files/common/files';
import { IExtensionsConfiguration, ConfigurationKey, ShowRecommendationsOnlyOnDemandKey, IExtensionsViewlet } from 'vs/workbench/parts/extensions/common/extensions';
// {{SQL CARBON EDIT}}
import { IExtensionsConfiguration, ConfigurationKey, ShowRecommendationsOnlyOnDemandKey, IExtensionsViewlet, ExtensionsPolicyKey, ExtensionsPolicy } from 'vs/workbench/parts/extensions/common/extensions';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import * as pfs from 'vs/base/node/pfs';
@@ -111,7 +112,9 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
) {
super();
if (!this.isEnabled()) {
// {{SQL CARBON EDIT}}
let extensionPolicy: string = this.configurationService.getValue<string>(ExtensionsPolicyKey);
if (!this.isEnabled() || extensionPolicy === ExtensionsPolicy.allowNone) {
return;
}
@@ -408,7 +411,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
getOtherRecommendations(): TPromise<IExtensionRecommendation[]> {
// {{SQL CARBON EDIT}}
let recommendations = Object.keys(this._exeBasedRecommendations);
let recommendations = Object.keys(this._exeBasedRecommendations).concat(this._recommendations);
shuffle(recommendations, this.sessionSeed);
return TPromise.as(recommendations.map(extensionId => {
const sources: ExtensionRecommendationSource[] = [];

View File

@@ -17,7 +17,8 @@ import { ExtensionTipsService } from 'vs/workbench/parts/extensions/electron-bro
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/parts/output/common/output';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { VIEWLET_ID, IExtensionsWorkbenchService } from '../common/extensions';
// {{SQL CARBON EDIT}}
import { VIEWLET_ID, IExtensionsWorkbenchService, ExtensionsPolicy } from '../common/extensions';
import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService';
import {
OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowRecommendedKeymapExtensionsAction, ShowPopularExtensionsAction,
@@ -231,6 +232,13 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
type: 'boolean',
description: localize('extensionsCloseExtensionDetailsOnViewChange', "When enabled, editors with extension details will be automatically closed upon navigating away from the Extensions View."),
default: false
},
// {{SQL CARBON EDIT}}
'extensions.extensionsPolicy': {
type: 'string',
description: localize('extensionsPolicy', "Sets the security policy for downloading extensions."),
scope: ConfigurationScope.APPLICATION,
default: ExtensionsPolicy.allowAll
}
}
});

View File

@@ -16,7 +16,8 @@ import * as json from 'vs/base/common/json';
import { ActionItem, IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions';
// {{SQL CARBON EDIT}}
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey, ExtensionsPolicyKey, ExtensionsPolicy } from 'vs/workbench/parts/extensions/common/extensions';
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/parts/extensions/common/extensionsFileTemplate';
import { LocalExtensionType, IExtensionEnablementService, IExtensionTipsService, EnablementState, ExtensionsLabel, IExtensionManagementServer, IExtensionManagementServerService, IExtensionRecommendation, ExtensionRecommendationSource, IExtensionGalleryService, IGalleryExtension, ILocalExtension, IExtensionsConfigContent } from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
@@ -52,6 +53,8 @@ import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorG
import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput';
import product from 'vs/platform/node/product';
import { ContextSubMenu } from 'vs/base/browser/contextmenu';
// {{SQL CARBON EDIT}}
import { IStorageService } from 'vs/platform/storage/common/storage';
const promptDownloadManually = (extension: IGalleryExtension, message: string, instantiationService: IInstantiationService, notificationService: INotificationService, openerService: IOpenerService) => {
const downloadUrl = `${product.extensionsGallery.serviceUrl}/publishers/${extension.publisher}/vsextensions/${extension.name}/${extension.version}/vspackage`;
@@ -2656,33 +2659,84 @@ export class InstallVSIXAction extends Action {
label = InstallVSIXAction.LABEL,
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
@INotificationService private notificationService: INotificationService,
@IWindowService private windowService: IWindowService
@IWindowService private windowService: IWindowService,
// {{SQL CARBON EDIT}}
@IConfigurationService private configurationService: IConfigurationService,
@IStorageService private storageService: IStorageService
) {
super(id, label, 'extension-action install-vsix', true);
}
run(): TPromise<any> {
return this.windowService.showOpenDialog({
title: localize('installFromVSIX', "Install from VSIX"),
filters: [{ name: 'VSIX Extensions', extensions: ['vsix'] }],
properties: ['openFile'],
buttonLabel: mnemonicButtonLabel(localize({ key: 'installButton', comment: ['&& denotes a mnemonic'] }, "&&Install"))
}).then(result => {
if (!result) {
return TPromise.as(null);
}
// {{SQL CARBON EDIT}}
let extensionPolicy = this.configurationService.getValue<string>(ExtensionsPolicyKey);
if (extensionPolicy === ExtensionsPolicy.allowAll) {
return this.windowService.showOpenDialog({
title: localize('installFromVSIX', "Install from VSIX"),
filters: [{ name: 'VSIX Extensions', extensions: ['vsix'] }],
properties: ['openFile'],
buttonLabel: mnemonicButtonLabel(localize({ key: 'installButton', comment: ['&& denotes a mnemonic'] }, "&&Install"))
}).then(result => {
if (!result) {
return TPromise.as(null);
}
return TPromise.join(result.map(vsix => {
// {{SQL CARBON EDIT}}
if (!this.storageService.getBoolean(vsix)) {
this.notificationService.prompt(
Severity.Warning,
localize('thirdPartyExtension.vsix', 'This is a third party extension and might involve security risks. Are you sure you want to install this extension?'),
[
{
label: localize('thirdPartExt.yes', 'Yes'),
run: () => {
this.extensionsWorkbenchService.install(vsix).then(() => {
this.notificationService.prompt(
Severity.Info,
localize('InstallVSIXAction.success', "Successfully installed the extension. Reload to enable it."),
[{
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
run: () => this.windowService.reloadWindow()
}]
);
});
}
},
{
label: localize('thirdPartyExt.no', 'No'),
run: () => { return TPromise.as(null); }
},
{
label: localize('thirdPartyExt.dontShowAgain', 'Don\'t Show Again'),
isSecondary: true,
run: () => {
this.storageService.store(vsix, true);
return TPromise.as(null);
}
}
]
);
} else {
this.extensionsWorkbenchService.install(vsix).then(() => {
this.notificationService.prompt(
Severity.Info,
localize('InstallVSIXAction.success', "Successfully installed the extension. Reload to enable it."),
[{
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
run: () => this.windowService.reloadWindow()
}]
);
});
}
return TPromise.join(result.map(vsix => this.extensionsWorkbenchService.install(vsix))).then(() => {
this.notificationService.prompt(
Severity.Info,
localize('InstallVSIXAction.success', "Successfully installed the extension. Reload to enable it."),
[{
label: localize('InstallVSIXAction.reloadNow', "Reload Now"),
run: () => this.windowService.reloadWindow()
}]
);
}));
});
});
// {{SQL CARBON EDIT}}
} else {
this.notificationService.error(localize('InstallVSIXAction.allowNone', 'Your extension policy does not allow downloading extensions. Please change your extension policy and try again.'));
return TPromise.as(null);
}
}
}

View File

@@ -26,7 +26,8 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IWindowService } from 'vs/platform/windows/common/windows';
import Severity from 'vs/base/common/severity';
import URI from 'vs/base/common/uri';
import { IExtension, IExtensionDependencies, ExtensionState, IExtensionsWorkbenchService, AutoUpdateConfigurationKey, AutoCheckUpdatesConfigurationKey } from 'vs/workbench/parts/extensions/common/extensions';
// {{SQL CARBON EDIT}}
import { IExtension, IExtensionDependencies, ExtensionState, IExtensionsWorkbenchService, AutoUpdateConfigurationKey, AutoCheckUpdatesConfigurationKey, ExtensionsPolicyKey, ExtensionsPolicy } from 'vs/workbench/parts/extensions/common/extensions';
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
import { ExtensionsInput } from 'vs/workbench/parts/extensions/common/extensionsInput';
@@ -701,6 +702,8 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
}
install(extension: string | IExtension): TPromise<void> {
// {{SQL CARBON EDIT}}
let extensionPolicy = this.configurationService.getValue<string>(ExtensionsPolicyKey);
if (typeof extension === 'string') {
return this.progressService.withProgress({
location: ProgressLocation.Extensions,
@@ -729,7 +732,16 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService,
title: nls.localize('installingMarketPlaceExtension', 'Installing extension from Marketplace....'),
source: `${extension.id}`
// {{SQL CARBON EDIT}}
}, () => this.downloadOrBrowse(ext));
}, () => {
if (extensionPolicy === ExtensionsPolicy.allowMicrosoft) {
if (ext.publisherDisplayName === 'Microsoft') {
return this.downloadOrBrowse(ext);
} else {
return TPromise.as(null);
}
}
return this.downloadOrBrowse(ext);
});
}
// {{SQL CARBON EDIT}}

View File

@@ -60,7 +60,8 @@ suite('ExtensionsActions Test', () => {
instantiationService.stub(IWindowService, TestWindowService);
instantiationService.stub(IWorkspaceContextService, new TestContextService());
instantiationService.stub(IConfigurationService, { onDidUpdateConfiguration: () => { }, onDidChangeConfiguration: () => { }, getConfiguration: () => ({}) });
// {{SQL CARBON EDIT}}
instantiationService.stub(IConfigurationService, { onDidUpdateConfiguration: () => { }, onDidChangeConfiguration: () => { }, getConfiguration: () => ({}), getValue: () => { } });
instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService);

View File

@@ -9,6 +9,8 @@ import { GettingStarted } from './gettingStarted';
import { TelemetryOptOut } from './telemetryOptOut';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
// {{SQL CARBON EDIT}} - Add preview feature switch
import { EnablePreviewFeatures } from 'sql/workbench/electron-browser/enablePreviewFeatures';
// {{SQL CARBON EDIT}}
// Registry
@@ -22,3 +24,8 @@ Registry
Registry
.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(TelemetryOptOut, LifecyclePhase.Eventually);
// {{SQL CARBON EDIT}} - Add preview feature switch
Registry
.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench)
.registerWorkbenchContribution(EnablePreviewFeatures, LifecyclePhase.Eventually);

View File

@@ -29,6 +29,7 @@ import { coalesce } from 'vs/base/common/arrays';
import { isCodeEditor, isDiffEditor, ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorGroupView, IEditorOpeningEvent, EditorGroupsServiceImpl, EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
import { IUriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay';
import { convertEditorInput } from 'sql/parts/common/customInputConverter';
type ICachedEditorInput = ResourceEditorInput | IFileEditorInput | DataUriEditorInput;
@@ -232,13 +233,18 @@ export class EditorService extends Disposable implements EditorServiceImpl {
return this.doOpenEditor(targetGroup, editor, editorOptions);
}
// {{SQL CARBON EDIT}}
// Untyped Text Editor Support
const textInput = <IResourceEditor>editor;
const typedInput = this.createInput(textInput);
let typedInput = this.createInput(textInput);
if (typedInput) {
const editorOptions = TextEditorOptions.from(textInput);
const targetGroup = this.findTargetGroup(typedInput, editorOptions, optionsOrGroup as IEditorGroup | GroupIdentifier);
// {{SQL CARBON EDIT}}
// Convert input into custom type if it's one of the ones we support
typedInput = convertEditorInput(typedInput, editorOptions, this.instantiationService);
return this.doOpenEditor(targetGroup, typedInput, editorOptions);
}