Merge master

This commit is contained in:
Kevin Cunnane
2018-11-04 15:15:27 -08:00
41 changed files with 655 additions and 327 deletions

View File

@@ -3,6 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Color } from 'vs/base/common/color';
import { Event, Emitter } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Widget } from 'vs/base/browser/ui/widget';
@@ -15,9 +16,14 @@ export interface ICheckboxOptions {
ariaLabel?: string;
}
export interface ICheckboxStyles {
disabledCheckboxForeground?: Color;
}
export class Checkbox extends Widget {
private _el: HTMLInputElement;
private _label: HTMLSpanElement;
private disabledCheckboxForeground: Color;
private _onChange = new Emitter<boolean>();
public readonly onChange: Event<boolean> = this._onChange.event;
@@ -65,6 +71,7 @@ export class Checkbox extends Widget {
public set enabled(val: boolean) {
this._el.disabled = !val;
this.updateStyle();
}
public get enabled(): boolean {
@@ -90,4 +97,13 @@ export class Checkbox extends Widget {
public enable(): void {
this.enabled = true;
}
public style(styles: ICheckboxStyles): void {
this.disabledCheckboxForeground = styles.disabledCheckboxForeground;
this.updateStyle();
}
private updateStyle(): void {
this._label.style.color = !this.enabled && this.disabledCheckboxForeground ? this.disabledCheckboxForeground.toString() : 'inherit';
}
}

View File

@@ -66,14 +66,11 @@
}
.monaco-shell .modal.flyout-dialog .modal-body,
.monaco-shell .modal.flyout-dialog .angular-modal-body {
margin-bottom: auto;
height: 100%;
}
.monaco-shell .modal.flyout-dialog .angular-modal-body,
/* Style for body and footer in modal dialog. This should be applied to dialog created with angular component. */
.monaco-shell .modal.flyout-dialog .modal-body-and-footer {
height: 100%;
flex: 1 1;
overflow: hidden;
}
/* modl body content style(excluding dialogErrorMessage section) for angulr component dialog */
@@ -85,6 +82,8 @@
.modal.flyout-dialog .angular-form {
height: 100%;
display: flex;
flex-direction: column;
}
.modal.flyout-dialog .dialog-label {
@@ -105,10 +104,6 @@
padding-left: 4px;
}
.modal.flyout-dialog .modal-body {
overflow-y: auto;
}
.vs-dark.monaco-shell .modal.flyout-dialog .input {
background-color: #3C3C3C;
}
@@ -187,7 +182,6 @@
.modal.flyout-dialog .dialog-message-header {
overflow: hidden;
overflow-y: hidden;
display: flex;
flex-direction: row;
}

View File

@@ -27,7 +27,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
export const MODAL_SHOWING_KEY = 'modalShowing';
export const MODAL_SHOWING_CONTEXT = new RawContextKey<Array<string>>(MODAL_SHOWING_KEY, []);
const INFO_ALT_TEXT = localize('infoAltText', 'Infomation');
const INFO_ALT_TEXT = localize('infoAltText', 'Information');
const WARNING_ALT_TEXT = localize('warningAltText', 'Warning');
const ERROR_ALT_TEXT = localize('errorAltText', 'Error');
const SHOW_DETAILS_TEXT = localize('showMessageDetails', 'Show Details');

View File

@@ -89,10 +89,6 @@
-moz-transition-property: width;
}
.hc-black .split-view-view .action-label {
background: none;
}
.hc-black .split-view-view > .header .action-label:before {
top: 4px !important;
}

View File

@@ -12,6 +12,7 @@ export const tableHeaderForeground = registerColor('table.headerForeground', { d
export const disabledInputBackground = registerColor('input.disabled.background', { dark: '#444444', light: '#dcdcdc', hc: Color.black }, nls.localize('disabledInputBoxBackground', "Disabled Input box background."));
export const disabledInputForeground = registerColor('input.disabled.foreground', { dark: '#888888', light: '#888888', hc: foreground }, nls.localize('disabledInputBoxForeground', "Disabled Input box foreground."));
export const buttonFocusOutline = registerColor('button.focusOutline', { dark: '#eaeaea', light: '#666666', hc: null }, nls.localize('buttonFocusOutline', "Button outline color when focused."));
export const disabledCheckboxForeground = registerColor('checkbox.disabled.foreground', { dark: '#888888', light: '#888888', hc: Color.black }, nls.localize('disabledCheckboxforeground', "Disabled checkbox foreground."));
export const listFocusAndSelectionBackground = registerColor('list.focusAndSelectionBackground', { dark: '#2c3295', light: '#2c3295', hc: null }, nls.localize('listFocusAndSelectionBackground', "List/Table background color for the selected and focus item when the list/table is active"));

View File

@@ -255,3 +255,10 @@ export function attachButtonStyler(widget: IThemable, themeService: IThemeServic
buttonFocusOutline: (style && style.buttonFocusOutline) || sqlcolors.buttonFocusOutline
}, widget);
}
export function attachCheckboxStyler(widget: IThemable, themeService: IThemeService, style?: { disabledCheckboxForeground?: cr.ColorIdentifier })
: IDisposable {
return attachStyler(themeService, {
disabledCheckboxForeground: (style && style.disabledCheckboxForeground) || sqlcolors.disabledCheckboxForeground
}, widget);
}

View File

@@ -0,0 +1,17 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export interface ICommandLineProcessing {
_serviceBrand: any;
/**
* Interprets the various Azure Data Studio-specific command line switches and
* performs the requisite tasks such as connecting to a server
*/
processCommandLine() : void;
}
export const ICommandLineProcessing = createDecorator<ICommandLineProcessing>('commandLineService');

View File

@@ -0,0 +1,75 @@
/*---------------------------------------------------------------------------------------------
* 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 { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { ICommandLineProcessing } from 'sql/parts/commandLine/common/commandLine';
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import * as Constants from 'sql/parts/connection/common/constants';
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
import * as platform from 'vs/platform/registry/common/platform';
import { ConnectionProviderProperties, IConnectionProviderRegistry, Extensions as ConnectionProviderExtensions } from 'sql/workbench/parts/connection/common/connectionProviderExtension';
import * as TaskUtilities from 'sql/workbench/common/taskUtilities';
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
export class CommandLineService implements ICommandLineProcessing {
private _connectionProfile: ConnectionProfile;
private _showConnectionDialog: boolean;
constructor(
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
@IEnvironmentService private _environmentService: IEnvironmentService,
@IQueryEditorService private _queryEditorService: IQueryEditorService,
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
@IEditorService private _editorService: IEditorService,
) {
let profile = null;
if (this._environmentService && this._environmentService.args.server) {
profile = new ConnectionProfile(_capabilitiesService, null);
// We want connection store to use any matching password it finds
profile.savePassword = true;
profile.providerName = Constants.mssqlProviderName;
profile.serverName = _environmentService.args.server;
profile.databaseName = _environmentService.args.database ? _environmentService.args.database : '';
profile.userName = _environmentService.args.user ? _environmentService.args.user : '';
profile.authenticationType = _environmentService.args.integrated ? 'Integrated' : 'SqlLogin';
profile.connectionName = '';
profile.setOptionValue('applicationName', Constants.applicationName);
profile.setOptionValue('databaseDisplayName', profile.databaseName);
profile.setOptionValue('groupId', profile.groupId);
}
this._connectionProfile = profile;
const registry = platform.Registry.as<IConnectionProviderRegistry>(ConnectionProviderExtensions.ConnectionProviderContributions);
let sqlProvider = registry.getProperties(Constants.mssqlProviderName);
// We can't connect to object explorer until the MSSQL connection provider is registered
if (sqlProvider) {
this.processCommandLine();
} else {
registry.onNewProvider(e => {
if (e.id === Constants.mssqlProviderName) {
this.processCommandLine();
}
});
}
}
public _serviceBrand: any;
public processCommandLine(): void {
if (!this._connectionProfile && !this._connectionManagementService.hasRegisteredServers()) {
// prompt the user for a new connection on startup if no profiles are registered
this._connectionManagementService.showConnectionDialog();
} else if (this._connectionProfile) {
this._connectionManagementService.connectIfNotConnected(this._connectionProfile, 'connection')
.then(result => TaskUtilities.newQuery(this._connectionProfile,
this._connectionManagementService,
this._queryEditorService,
this._objectExplorerService,
this._editorService))
.catch(() => { });
}
}
}

View File

@@ -77,7 +77,6 @@ export class ConnectionManagementService extends Disposable implements IConnecti
private _onConnectRequestSent = new Emitter<void>();
private _onConnectionChanged = new Emitter<IConnectionParams>();
private _onLanguageFlavorChanged = new Emitter<sqlops.DidChangeLanguageFlavorParams>();
private _connectionGlobalStatus = new ConnectionGlobalStatus(this._statusBarService);
private _configurationEditService: ConfigurationEditingService;
@@ -124,16 +123,6 @@ export class ConnectionManagementService extends Disposable implements IConnecti
100 /* High Priority */
));
if (_capabilitiesService && Object.keys(_capabilitiesService.providers).length > 0 && !this.hasRegisteredServers()) {
// prompt the user for a new connection on startup if no profiles are registered
this.showConnectionDialog();
} else if (_capabilitiesService && !this.hasRegisteredServers()) {
_capabilitiesService.onCapabilitiesRegistered(e => {
// prompt the user for a new connection on startup if no profiles are registered
this.showConnectionDialog();
});
}
const registry = platform.Registry.as<IConnectionProviderRegistry>(ConnectionProviderExtensions.ConnectionProviderContributions);
let providerRegistration = (p: { id: string, properties: ConnectionProviderProperties }) => {
@@ -282,29 +271,30 @@ export class ConnectionManagementService extends Disposable implements IConnecti
* @param options to use after the connection is complete
*/
private tryConnect(connection: IConnectionProfile, owner: IConnectableInput, options?: IConnectionCompletionOptions): Promise<IConnectionResult> {
let self = this;
return new Promise<IConnectionResult>((resolve, reject) => {
// Load the password if it's not already loaded
this._connectionStore.addSavedPassword(connection).then(result => {
self._connectionStore.addSavedPassword(connection).then(result => {
let newConnection = result.profile;
let foundPassword = result.savedCred;
// If there is no password, try to load it from an existing connection
if (!foundPassword && this._connectionStore.isPasswordRequired(newConnection)) {
let existingConnection = this._connectionStatusManager.findConnectionProfile(connection);
if (!foundPassword && self._connectionStore.isPasswordRequired(newConnection)) {
let existingConnection = self._connectionStatusManager.findConnectionProfile(connection);
if (existingConnection && existingConnection.connectionProfile) {
newConnection.password = existingConnection.connectionProfile.password;
foundPassword = true;
}
}
// If the password is required and still not loaded show the dialog
if (!foundPassword && this._connectionStore.isPasswordRequired(newConnection) && !newConnection.password) {
resolve(this.showConnectionDialogOnError(connection, owner, { connected: false, errorMessage: undefined, callStack: undefined, errorCode: undefined }, options));
if (!foundPassword && self._connectionStore.isPasswordRequired(newConnection) && !newConnection.password) {
resolve(self.showConnectionDialogOnError(connection, owner, { connected: false, errorMessage: undefined, callStack: undefined, errorCode: undefined }, options));
} else {
// Try to connect
this.connectWithOptions(newConnection, owner.uri, options, owner).then(connectionResult => {
self.connectWithOptions(newConnection, owner.uri, options, owner).then(connectionResult => {
if (!connectionResult.connected && !connectionResult.errorHandled) {
// If connection fails show the dialog
resolve(this.showConnectionDialogOnError(connection, owner, connectionResult, options));
resolve(self.showConnectionDialogOnError(connection, owner, connectionResult, options));
} else {
//Resolve with the connection result
resolve(connectionResult);
@@ -390,7 +380,14 @@ export class ConnectionManagementService extends Disposable implements IConnecti
if (this._connectionStatusManager.isConnected(ownerUri)) {
resolve(this._connectionStatusManager.getOriginalOwnerUri(ownerUri));
} else {
this.connect(connection, ownerUri).then(connectionResult => {
const options: IConnectionCompletionOptions = {
saveTheConnection: false,
showConnectionDialogOnError: true,
showDashboard: purpose === 'dashboard',
params: undefined,
showFirewallRuleOnError: true,
};
this.connect(connection, ownerUri, options).then(connectionResult => {
if (connectionResult && connectionResult.connected) {
resolve(this._connectionStatusManager.getOriginalOwnerUri(ownerUri));
} else {

View File

@@ -17,7 +17,7 @@ import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { ConnectionOptionSpecialType } from 'sql/workbench/api/common/sqlExtHostTypes';
import * as Constants from 'sql/parts/connection/common/constants';
import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
import { attachInputBoxStyler, attachButtonStyler, attachEditableDropdownStyler } from 'sql/common/theme/styler';
import { attachButtonStyler, attachCheckboxStyler, attachEditableDropdownStyler, attachInputBoxStyler } from 'sql/common/theme/styler';
import { Dropdown } from 'sql/base/browser/ui/editableDropdown/dropdown';
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
@@ -274,6 +274,7 @@ export class ConnectionWidget {
this._toDispose.push(attachInputBoxStyler(this._passwordInputBox, this._themeService));
this._toDispose.push(styler.attachSelectBoxStyler(this._serverGroupSelectBox, this._themeService));
this._toDispose.push(attachButtonStyler(this._advancedButton, this._themeService));
this._toDispose.push(attachCheckboxStyler(this._rememberPasswordCheckBox, this._themeService));
if (this._authTypeSelectBox) {
// Theme styler

View File

@@ -14,7 +14,7 @@ import { ModalFooterStyle } from 'sql/base/browser/ui/modal/modal';
import { CategoryView } from 'sql/base/browser/ui/modal/optionsDialog';
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
import { SplitView } from 'sql/base/browser/ui/splitview/splitview';
import { attachButtonStyler, attachListBoxStyler, attachInputBoxStyler, attachSelectBoxStyler } from 'sql/common/theme/styler';
import { attachButtonStyler, attachListBoxStyler, attachInputBoxStyler, attachSelectBoxStyler, attachCheckboxStyler } from 'sql/common/theme/styler';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import * as BackupConstants from 'sql/parts/disasterRecovery/backup/constants';
import { IBackupService, IBackupUiService, TaskExecutionMode } from 'sql/parts/disasterRecovery/backup/common/backupService';
@@ -523,6 +523,11 @@ export class BackupComponent {
this._toDispose.push(attachInputBoxStyler(this.mediaNameBox, this.themeService));
this._toDispose.push(attachInputBoxStyler(this.mediaDescriptionBox, this.themeService));
this._toDispose.push(attachInputBoxStyler(this.backupRetainDaysBox, this.themeService));
this._toDispose.push(attachCheckboxStyler(this.copyOnlyCheckBox, this.themeService));
this._toDispose.push(attachCheckboxStyler(this.encryptCheckBox, this.themeService));
this._toDispose.push(attachCheckboxStyler(this.verifyCheckBox, this.themeService));
this._toDispose.push(attachCheckboxStyler(this.checksumCheckBox, this.themeService));
this._toDispose.push(attachCheckboxStyler(this.continueOnErrorCheckBox, this.themeService));
this._toDispose.push(this.backupTypeSelectBox.onDidSelect(selected => this.onBackupTypeChanged()));
this.addButtonClickHandler(this.addPathButton, () => this.onAddClick());

View File

@@ -17,7 +17,7 @@
}
.backup-dialog {
height: calc(100% - 15px)
height: 100%
}
.backup-dialog .advanced-main-header {

View File

@@ -33,7 +33,7 @@ import { Table } from 'sql/base/browser/ui/table/table';
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
import * as DialogHelper from 'sql/base/browser/ui/modal/dialogHelper';
import { Modal } from 'sql/base/browser/ui/modal/modal';
import { attachButtonStyler, attachModalDialogStyler, attachTableStyler, attachInputBoxStyler, attachSelectBoxStyler, attachEditableDropdownStyler } from 'sql/common/theme/styler';
import { attachButtonStyler, attachModalDialogStyler, attachTableStyler, attachInputBoxStyler, attachSelectBoxStyler, attachEditableDropdownStyler, attachCheckboxStyler } from 'sql/common/theme/styler';
import * as TelemetryKeys from 'sql/common/telemetryKeys';
import * as BackupConstants from 'sql/parts/disasterRecovery/backup/constants';
import { RestoreViewModel, RestoreOptionParam, SouceDatabaseNamesParam } from 'sql/parts/disasterRecovery/restore/restoreViewModel';
@@ -532,6 +532,7 @@ export class RestoreDialog extends Modal {
ariaLabel: label
});
});
this._register(attachCheckboxStyler(checkbox, this._themeService));
return checkbox;
}

View File

@@ -1,8 +1,7 @@
div.qp-node {
background-color: #FFFFCC;
margin: 2px;
padding: 2px;
border: 1px solid black;
border: 1px solid;
}
div.qp-statement-header {
margin: 2px;
@@ -33,8 +32,7 @@ div[class|='qp-icon'] {
.qp-tt {
top: 4em;
left: 2em;
border: 1px solid black;
background-color: #FFFFEE;
border: 1px solid;
padding: 2px;
width: 30em;
}
@@ -56,7 +54,7 @@ div[class|='qp-icon'] {
.qp-tt td,
.qp-tt th {
font-size: 11px;
border-bottom: solid 1px Black;
border-bottom: solid 1px;
padding: 1px;
}
@@ -204,8 +202,6 @@ div.qp-node:hover .qp-tt {
.qp-root {
display: table;
position: relative;
background-color: #fff;
color: #000;
}
.qp-root svg {

View File

@@ -219,14 +219,10 @@ export class NewStepAction extends Action {
public run(context: JobHistoryComponent): TPromise<boolean> {
let ownerUri = context.ownerUri;
let jobName = context.agentJobInfo.name;
let server = context.serverName;
let stepId = 0;
if (context.agentJobHistoryInfo && context.agentJobHistoryInfo.steps) {
stepId = context.agentJobHistoryInfo.steps.length + 1;
}
let jobInfo = context.agentJobInfo;
return new TPromise<boolean>((resolve, reject) => {
resolve(this._commandService.executeCommand('agent.openNewStepDialog', ownerUri, jobName, server, stepId));
resolve(this._commandService.executeCommand('agent.openNewStepDialog', ownerUri, server, jobInfo , null));
});
}
}

View File

@@ -923,33 +923,17 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
let steps = this.jobSteps[jobId];
job[0].JobSteps = steps;
}
let jobHistories = this.jobHistories[job[0].jobId];
let schedules: sqlops.AgentJobScheduleInfo[] = this.jobSchedules[job[0].jobId];
let alerts: sqlops.AgentAlertInfo[] = this.jobAlerts[job[0].jobId];
if (jobHistories && jobHistories[jobHistories.length-1]) {
// add schedules
if (schedules && schedules.length > 0) {
if (!job[0].JobSchedules) {
job[0].JobSchedules = [];
}
if (job[0].JobSchedules.length !== schedules.length) {
job[0].JobSchedules = [];
schedules.forEach(schedule => {
job[0].JobSchedules.push(schedule);
});
}
}
// add alerts
if (!job[0].Alerts) {
job[0].Alerts = [];
}
if (job[0].Alerts.length !== alerts.length) {
job[0].Alerts = [];
alerts.forEach(alert => {
job[0].Alerts.push(alert);
});
}
// add schedules
if (this.jobSchedules && this.jobSchedules[jobId]) {
let schedules = this.jobSchedules[jobId];
job[0].JobSchedules = schedules;
}
// add alerts
if (this.jobAlerts && this.jobAlerts[jobId]) {
let alerts = this.jobAlerts[jobId];
job[0].Alerts = alerts;
}
return job && job.length > 0 ? job[0] : undefined;
}

View File

@@ -14,6 +14,8 @@ import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
import { Checkbox, ICheckboxOptions } from 'sql/base/browser/ui/checkbox/checkbox';
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
import { attachCheckboxStyler } from 'sql/common/theme/styler';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
@Component({
selector: 'modelview-checkbox',
@@ -30,7 +32,8 @@ export default class CheckBoxComponent extends ComponentBase implements ICompone
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
@Inject(forwardRef(() => ElementRef)) el: ElementRef) {
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
@Inject(forwardRef(() => ElementRef)) el: ElementRef,) {
super(changeRef, el);
}
@@ -55,6 +58,7 @@ export default class CheckBoxComponent extends ComponentBase implements ICompone
args: e
});
}));
this._register(attachCheckboxStyler(this._input, this.themeService));
}
}

View File

@@ -326,7 +326,7 @@ export class ChartView extends Disposable implements IPanelView {
this.optionDisposables.push(attachInputBoxStyler(numberInput, this._themeService));
break;
case ControlType.dateInput:
let dateInput = new InputBox(optionContainer, this._contextViewService, { type: 'date' });
let dateInput = new InputBox(optionContainer, this._contextViewService, { type: 'datetime-local' });
dateInput.value = value || '';
dateInput.onDidChange(e => {
if (this.options[option.configEntry] !== e) {

View File

@@ -19,7 +19,7 @@ import { ChartType, DataDirection, LegendPosition, DataType, IPointDataSet, cust
const noneLineGraphs = [ChartType.Doughnut, ChartType.Pie];
const timeSeriesScales = {
const timeSeriesScales: ChartJs.ChartOptions = {
scales: {
xAxes: [{
type: 'time',
@@ -64,7 +64,7 @@ export class Graph implements IInsight {
this._theme = e;
this.data = this._data;
});
this._options = mixin(options, defaultOptions, false);
this.options = mixin(options, defaultOptions, false);
let canvasContainer = document.createElement('div');
canvasContainer.style.width = '100%';
@@ -89,9 +89,12 @@ export class Graph implements IInsight {
}
public set data(data: IInsightData) {
if (!data) {
return;
}
this._data = data;
let chartData: Array<ChartJs.ChartDataSets>;
let labels: Array<string>;
let chartData: Array<ChartJs.ChartDataSets>;
if (this.options.dataDirection === DataDirection.Horizontal) {
if (this.options.labelFirstColumn) {
@@ -158,19 +161,19 @@ export class Graph implements IInsight {
if (this.chartjs) {
this.chartjs.data.datasets = chartData;
this.chartjs.config.type = this.options.type;
this.chartjs.data.labels = labels;
// we don't want to include lables for timeSeries
this.chartjs.data.labels = this.originalType === 'timeSeries' ? [] : labels;
this.chartjs.options = this.transformOptions(this.options);
this.chartjs.update(0);
} else {
this.chartjs = new ChartJs(this.canvas.getContext('2d'), {
data: {
labels: labels,
// we don't want to include lables for timeSeries
labels: this.originalType === 'timeSeries' ? [] : labels,
datasets: chartData
},
type: this.options.type,
options: {
maintainAspectRatio: false
}
options: this.transformOptions(this.options)
});
}
}
@@ -197,15 +200,21 @@ export class Graph implements IInsight {
display: options.xAxisLabel ? true : false
},
ticks: {
fontColor: foreground,
max: options.xAxisMax,
min: options.xAxisMin
fontColor: foreground
},
gridLines: {
color: gridLines
}
}];
if (options.xAxisMax) {
retval.scales = mixin(retval.scales, { xAxes: [{ ticks: { max: options.xAxisMax } }] }, true, customMixin);
}
if (options.xAxisMin) {
retval.scales = mixin(retval.scales, { xAxes: [{ ticks: { min: options.xAxisMin } }] }, true, customMixin);
}
retval.scales.yAxes = [{
scaleLabel: {
fontColor: foreground,
@@ -213,22 +222,27 @@ export class Graph implements IInsight {
display: options.yAxisLabel ? true : false
},
ticks: {
fontColor: foreground,
max: options.yAxisMax,
min: options.yAxisMin
fontColor: foreground
},
gridLines: {
color: gridLines
}
}];
if (options.yAxisMax) {
retval.scales = mixin(retval.scales, { yAxes: [{ ticks: { max: options.yAxisMax } }] }, true, customMixin);
}
if (options.yAxisMin) {
retval.scales = mixin(retval.scales, { yAxes: [{ ticks: { min: options.yAxisMin } }] }, true, customMixin);
}
if (this.originalType === ChartType.TimeSeries) {
retval = mixin(retval, timeSeriesScales, true, customMixin);
if (options.xAxisMax) {
retval = mixin(retval, {
scales: {
xAxes: [{
type: 'time',
time: {
max: options.xAxisMax
}
@@ -241,7 +255,6 @@ export class Graph implements IInsight {
retval = mixin(retval, {
scales: {
xAxes: [{
type: 'time',
time: {
min: options.xAxisMin
}

View File

@@ -93,6 +93,10 @@ export class QueryPlan {
QP.showPlan(this.container, this._xml, {
jsTooltips: false
});
(<any>this.container.querySelectorAll('div.qp-tt')).forEach(toolTip=>{
toolTip.classList.add('monaco-editor');
toolTip.classList.add('monaco-editor-hover');
});
}
public get xml(): string {

View File

@@ -0,0 +1,176 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as Constants from 'sql/parts/connection/common/constants';
import * as Utils from 'sql/parts/connection/common/utils';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import * as sqlops from 'sqlops';
import { TPromise } from 'vs/base/common/winjs.base';
import * as assert from 'assert';
import * as TypeMoq from 'typemoq';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { CommandLineService } from 'sql/parts/commandLine/common/commandLineService';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
import { CapabilitiesService, ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService';
import { QueryEditorService } from 'sql/parts/query/services/queryEditorService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
import {
IConnectionManagementService, IConnectionDialogService, INewConnectionParams,
ConnectionType, IConnectableInput, IConnectionCompletionOptions, IConnectionCallbacks,
IConnectionParams, IConnectionResult, IServerGroupController, IServerGroupDialogCallbacks,
RunQueryOnConnectionMode
} from 'sql/parts/connection/common/connectionManagement';
import { ConnectionStore } from 'sql/parts/connection/common/connectionStore';
import { TestConnectionManagementService } from 'sqltest/stubs/connectionManagementService.test';
class TestParsedArgs implements ParsedArgs{
[arg: string]: any;
_: string[];
aad?: boolean;
add?: boolean;
database?:string;
debugBrkPluginHost?: string;
debugBrkSearch?: string;
debugId?: string;
debugPluginHost?: string;
debugSearch?: string;
diff?: boolean;
'disable-crash-reporter'?: string;
'disable-extension'?: string | string[];
'disable-extensions'?: boolean;
'disable-restore-windows'?: boolean;
'disable-telemetry'?: boolean;
'disable-updates'?: string;
'driver'?: string;
'enable-proposed-api'?: string | string[];
'export-default-configuration'?: string;
'extensions-dir'?: string;
extensionDevelopmentPath?: string;
extensionTestsPath?: string;
'file-chmod'?: boolean;
'file-write'?: boolean;
'folder-uri'?: string | string[];
goto?: boolean;
help?: boolean;
'install-extension'?: string | string[];
'install-source'?: string;
integrated?: boolean;
'list-extensions'?: boolean;
locale?: string;
log?: string;
logExtensionHostCommunication?: boolean;
'max-memory'?: number;
'new-window'?: boolean;
'open-url'?: boolean;
performance?: boolean;
'prof-append-timers'?: string;
'prof-startup'?: string;
'prof-startup-prefix'?: string;
'reuse-window'?: boolean;
server?: string;
'show-versions'?: boolean;
'skip-add-to-recently-opened'?: boolean;
'skip-getting-started'?: boolean;
'skip-release-notes'?: boolean;
status?: boolean;
'sticky-quickopen'?: boolean;
'uninstall-extension'?: string | string[];
'unity-launch'?: boolean; // Always open a new window, except if opening the first window or opening a file or folder as part of the launch.
'upload-logs'?: string;
user?: string;
'user-data-dir'?: string;
_urls?: string[];
verbose?: boolean;
version?: boolean;
wait?: boolean;
waitMarkerFilePath?: string;
}
suite('commandLineService tests', () => {
let capabilitiesService: CapabilitiesTestService;
let commandLineService : CommandLineService;
let environmentService : TypeMoq.Mock<EnvironmentService>;
let queryEditorService : TypeMoq.Mock<QueryEditorService>;
let editorService:TypeMoq.Mock<IEditorService>;
let objectExplorerService : TypeMoq.Mock<ObjectExplorerService>;
let connectionStore: TypeMoq.Mock<ConnectionStore>;
setup(() => {
capabilitiesService = new CapabilitiesTestService();
connectionStore = TypeMoq.Mock.ofType(ConnectionStore);
});
function getCommandLineService(connectionManagementService : IConnectionManagementService,
environmentService? : IEnvironmentService,
capabilitiesService? : ICapabilitiesService
) : CommandLineService
{
let service= new CommandLineService(
connectionManagementService,
capabilitiesService,
environmentService,
undefined,
undefined,
undefined
);
return service;
}
test('processCommandLine shows connection dialog by default', done => {
const connectionManagementService : TypeMoq.Mock<IConnectionManagementService>
= TypeMoq.Mock.ofType<IConnectionManagementService>(TestConnectionManagementService, TypeMoq.MockBehavior.Strict);
connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable();
connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => false);
connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.verifiable(TypeMoq.Times.never());
let service = getCommandLineService(connectionManagementService.object);
service.processCommandLine();
connectionManagementService.verifyAll();
done();
});
test('processCommandLine does nothing if registered servers exist and no server name is provided', done => {
const connectionManagementService : TypeMoq.Mock<IConnectionManagementService>
= TypeMoq.Mock.ofType<IConnectionManagementService>(TestConnectionManagementService, TypeMoq.MockBehavior.Strict);
connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never());
connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true);
connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.verifiable(TypeMoq.Times.never());
let service = getCommandLineService(connectionManagementService.object);
service.processCommandLine();
connectionManagementService.verifyAll();
done();
});
test('processCommandLine opens a new connection if a server name is passed', done => {
const connectionManagementService : TypeMoq.Mock<IConnectionManagementService>
= TypeMoq.Mock.ofType<IConnectionManagementService>(TestConnectionManagementService, TypeMoq.MockBehavior.Strict);
const environmentService : TypeMoq.Mock<IEnvironmentService> = TypeMoq.Mock.ofType<IEnvironmentService>(EnvironmentService);
const args : TestParsedArgs = new TestParsedArgs();
args.server = 'myserver';
args.database = 'mydatabase';
environmentService.setup(e => e.args).returns(() => args).verifiable(TypeMoq.Times.atLeastOnce());
connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never());
connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true).verifiable(TypeMoq.Times.atMostOnce());
connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.isAny(), 'connection'))
.returns(() => new Promise<string>((resolve, reject) => { reject('unused');}))
.verifiable(TypeMoq.Times.once());
let service = getCommandLineService(connectionManagementService.object, environmentService.object, capabilitiesService);
service.processCommandLine();
environmentService.verifyAll();
connectionManagementService.verifyAll();
done();
});
});

View File

@@ -62,6 +62,13 @@ export interface ParsedArgs {
'upload-logs'?: string;
'driver'?: string;
'driver-verbose'?: boolean;
// {{SQL CARBON EDIT}}
aad?: boolean;
database?: string;
integrated?: boolean;
server?: string;
user?: string;
// {{SQL CARBON EDIT}}
}
export const IEnvironmentService = createDecorator<IEnvironmentService>('environmentService');

View File

@@ -33,7 +33,12 @@ const options: minimist.Opts = {
'export-default-configuration',
'install-source',
'upload-logs',
'driver'
'driver',
// {{SQL CARBON EDIT}}
'database',
'server',
'user',
// {{SQL CARBON EDIT}}
],
boolean: [
'help',
@@ -66,7 +71,11 @@ const options: minimist.Opts = {
'status',
'file-write',
'file-chmod',
'driver-verbose'
'driver-verbose',
// {{SQL CARBON EDIT}}
'aad',
'integrated',
// {{SQL CARBON EDIT}}
],
alias: {
add: 'a',
@@ -85,6 +94,12 @@ const options: minimist.Opts = {
'debugBrkPluginHost': 'inspect-brk-extensions',
'debugSearch': 'inspect-search',
'debugBrkSearch': 'inspect-brk-search',
// {{SQL CARBON EDIT}}
database: 'D',
integrated: 'E',
server: 'S',
user: 'U',
// {{SQL CARBON EDIT}}
}
};

View File

@@ -165,6 +165,8 @@ import { DashboardViewService } from 'sql/services/dashboard/common/dashboardVie
import { ModelViewService } from 'sql/services/modelComponents/modelViewServiceImpl';
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
import { DashboardService } from 'sql/services/dashboard/common/dashboardServiceImpl';
import { NotebookService } from 'sql/services/notebook/notebookServiceImpl';
import { INotebookService } from 'sql/services/notebook/notebookService';
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@@ -172,8 +174,10 @@ import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'
import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IUriDisplayService, UriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay';
import { NotebookService } from 'sql/services/notebook/notebookServiceImpl';
import { INotebookService } from 'sql/services/notebook/notebookService';
// {{SQL CARBON EDIT}}
import { ICommandLineProcessing } from 'sql/parts/commandLine/common/commandLine';
import { CommandLineService } from 'sql/parts/commandLine/common/commandLineService';
// {{SQL CARBON EDIT}}
interface WorkbenchParams {
configuration: IWindowConfiguration;
@@ -579,7 +583,9 @@ export class Workbench extends Disposable implements IPartService {
serviceCollection.set(INotebookService, notebookService);
serviceCollection.set(IAccountPickerService, this.instantiationService.createInstance(AccountPickerService));
serviceCollection.set(IProfilerService, this.instantiationService.createInstance(ProfilerService));
// {{SQL CARBON EDIT}}
serviceCollection.set(ICommandLineProcessing, this.instantiationService.createInstance(CommandLineService));
// {{SQL CARBON EDIT}}
this._register(toDisposable(() => connectionManagementService.shutdown()));
this._register(toDisposable(() => accountManagementService.shutdown()));
this._register(toDisposable(() => notebookService.shutdown()));