diff --git a/extensions/agent/package.json b/extensions/agent/package.json index 1a3f5612f6..73773325e8 100644 --- a/extensions/agent/package.json +++ b/extensions/agent/package.json @@ -2,7 +2,7 @@ "name": "agent", "displayName": "SQL Server Agent", "description": "Manage and troubleshoot SQL Server Agent jobs", - "version": "0.34.0", + "version": "0.35.0", "publisher": "Microsoft", "preview": true, "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt", diff --git a/extensions/agent/src/data/alertData.ts b/extensions/agent/src/data/alertData.ts index bcef62b4ea..295661b2cc 100644 --- a/extensions/agent/src/data/alertData.ts +++ b/extensions/agent/src/data/alertData.ts @@ -9,6 +9,7 @@ import * as vscode from 'vscode'; import * as sqlops from 'sqlops'; import { AgentUtils } from '../agentUtils'; import { IAgentDialogData, AgentDialogMode } from '../interfaces'; +import { JobData } from './jobData'; const localize = nls.loadMessageBundle(); @@ -45,8 +46,19 @@ export class AlertData implements IAgentDialogData { wmiEventNamespace: string; wmiEventQuery: string; - constructor(ownerUri:string, alertInfo: sqlops.AgentAlertInfo) { + private viaJobDialog: boolean; + private jobModel: JobData; + + constructor( + ownerUri:string, + alertInfo: sqlops.AgentAlertInfo, + jobModel?: JobData, + viaJobDialog: boolean = false + ) { this.ownerUri = ownerUri; + this.viaJobDialog = viaJobDialog; + this.jobModel = jobModel; + this.jobName = this.jobName ? this.jobName : this.jobModel.name; if (alertInfo) { this.dialogMode = AgentDialogMode.EDIT; @@ -60,7 +72,6 @@ export class AlertData implements IAgentDialogData { this.includeEventDescription = alertInfo.includeEventDescription.toString(); this.isEnabled = alertInfo.isEnabled; this.jobId = alertInfo.jobId; - this.jobName = alertInfo.jobName; this.lastOccurrenceDate = alertInfo.lastOccurrenceDate; this.lastResponseDate = alertInfo.lastResponseDate; this.messageId = alertInfo.messageId; @@ -82,10 +93,18 @@ export class AlertData implements IAgentDialogData { public async save() { let agentService = await AgentUtils.getAgentService(); - let result = this.dialogMode === AgentDialogMode.CREATE - ? await agentService.createAlert(this.ownerUri, this.toAgentAlertInfo()) - : await agentService.updateAlert(this.ownerUri, this.originalName, this.toAgentAlertInfo()); - + let result: any; + // if it's called via the job dialog, add it to the + // job model + if (this.viaJobDialog) { + if (this.jobModel) { + Promise.resolve(this); + return; + } + } else { + // has to be a create alert + result = await agentService.createAlert(this.ownerUri, this.toAgentAlertInfo()); + } if (!result || !result.success) { vscode.window.showErrorMessage( localize('alertData.saveErrorMessage', "Alert update failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown')); diff --git a/extensions/agent/src/data/jobData.ts b/extensions/agent/src/data/jobData.ts index 9f6f24cc87..1d512edd62 100644 --- a/extensions/agent/src/data/jobData.ts +++ b/extensions/agent/src/data/jobData.ts @@ -44,6 +44,7 @@ export class JobData implements IAgentDialogData { public jobSteps: sqlops.AgentJobStepInfo[]; public jobSchedules: sqlops.AgentJobScheduleInfo[]; public alerts: sqlops.AgentAlertInfo[]; + public jobId: string; constructor( ownerUri: string, @@ -62,6 +63,7 @@ export class JobData implements IAgentDialogData { this.jobSteps = jobInfo.JobSteps; this.jobSchedules = jobInfo.JobSchedules; this.alerts = jobInfo.Alerts; + this.jobId = jobInfo.jobId; } } @@ -115,7 +117,6 @@ export class JobData implements IAgentDialogData { let result = this.dialogMode === AgentDialogMode.CREATE ? await this._agentService.createJob(this.ownerUri, jobInfo) : await this._agentService.updateJob(this.ownerUri, this.originalName, jobInfo); - if (!result || !result.success) { vscode.window.showErrorMessage( localize('jobData.saveErrorMessage', "Job update failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown')); @@ -135,18 +136,6 @@ export class JobData implements IAgentDialogData { }; } - public addJobSchedule(schedule: sqlops.AgentJobScheduleInfo) { - if (this.jobSchedules) { - let existingSchedule = this.jobSchedules.find(item => item.name === schedule.name); - if (!existingSchedule) { - this.jobSchedules.push(schedule); - } - } else { - this.jobSchedules = []; - this.jobSchedules.push(schedule); - } - } - public toAgentJobInfo(): sqlops.AgentJobInfo { return { name: this.name, @@ -177,7 +166,7 @@ export class JobData implements IAgentDialogData { categoryType: 1, // LocalJob, hard-coding the value, corresponds to the target tab in SSMS lastRun: '', nextRun: '', - jobId: '' + jobId: this.jobId }; } } \ No newline at end of file diff --git a/extensions/agent/src/data/jobStepData.ts b/extensions/agent/src/data/jobStepData.ts index b84c73f566..a9624442f7 100644 --- a/extensions/agent/src/data/jobStepData.ts +++ b/extensions/agent/src/data/jobStepData.ts @@ -46,11 +46,13 @@ export class JobStepData implements IAgentDialogData { public retryInterval: number; public proxyName: string; private jobModel: JobData; + private viaJobDialog: boolean; - constructor(ownerUri:string, jobModel?: JobData) { + constructor(ownerUri:string, jobModel?: JobData, viaJobDialog: boolean = false) { this.ownerUri = ownerUri; this.jobName = jobModel.name; this.jobModel = jobModel; + this.viaJobDialog = viaJobDialog; } public async initialize() { @@ -59,18 +61,16 @@ export class JobStepData implements IAgentDialogData { public async save() { let agentService = await AgentUtils.getAgentService(); let result: any; - if (this.dialogMode === AgentDialogMode.CREATE) { - if (this.jobModel && this.jobModel.dialogMode === AgentDialogMode.CREATE) { - // create job -> create step + // if it's called via the job dialog, add it to the + // job model + if (this.viaJobDialog) { + if (this.jobModel) { Promise.resolve(this); return; - } else { - // edit job -> create step - result = await agentService.createJobStep(this.ownerUri, JobStepData.convertToAgentJobStepInfo(this)); } - } else if (this.jobModel && this.jobModel.dialogMode === AgentDialogMode.EDIT) { - // edit job -> edit step - result = await agentService.updateJobStep(this.ownerUri, this.stepName, JobStepData.convertToAgentJobStepInfo(this)); + } else { + // has to be a create step + result = await agentService.createJobStep(this.ownerUri, JobStepData.convertToAgentJobStepInfo(this)); } if (!result || !result.success) { vscode.window.showErrorMessage( diff --git a/extensions/agent/src/data/pickScheduleData.ts b/extensions/agent/src/data/pickScheduleData.ts index 15ad4c0f34..d2a46bf729 100644 --- a/extensions/agent/src/data/pickScheduleData.ts +++ b/extensions/agent/src/data/pickScheduleData.ts @@ -29,8 +29,6 @@ export class PickScheduleData implements IAgentDialogData { } public async save() { - let agentService = await AgentUtils.getAgentService(); this.selectedSchedule.jobName = this.jobName; - let result = await agentService.createJobSchedule(this.ownerUri, this.selectedSchedule); } } diff --git a/extensions/agent/src/dialogs/alertDialog.ts b/extensions/agent/src/dialogs/alertDialog.ts index 1e7bfe8b5e..b10ba8e40e 100644 --- a/extensions/agent/src/dialogs/alertDialog.ts +++ b/extensions/agent/src/dialogs/alertDialog.ts @@ -12,6 +12,7 @@ import { AgentUtils } from '../agentUtils'; import { AlertData } from '../data/alertData'; import { OperatorDialog } from './operatorDialog'; import { JobDialog } from './jobDialog'; +import { JobData } from '../data/jobData'; const localize = nls.loadMessageBundle(); @@ -148,14 +149,23 @@ export class AlertDialog extends AgentDialog { private delayMinutesTextBox: sqlops.InputBoxComponent; private delaySecondsTextBox: sqlops.InputBoxComponent; - private jobs: string[]; private databases: string[]; + private jobModel: JobData; + public jobId: string; + public jobName: string; - constructor(ownerUri: string, alertInfo: sqlops.AgentAlertInfo = undefined, jobs: string[]) { + constructor( + ownerUri: string, + jobModel: JobData, + alertInfo: sqlops.AgentAlertInfo = undefined, + viaJobDialog: boolean = false + ) { super(ownerUri, - new AlertData(ownerUri, alertInfo), + new AlertData(ownerUri, alertInfo, jobModel, viaJobDialog), alertInfo ? AlertDialog.EditDialogTitle : AlertDialog.CreateDialogTitle); - this.jobs = jobs; + this.jobModel = jobModel; + this.jobId = this.jobId ? this.jobId : this.jobModel.jobId; + this.jobName = this.jobName ? this.jobName : this.jobModel.name; } protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) { @@ -512,7 +522,8 @@ export class AlertDialog extends AgentDialog { protected updateModel() { this.model.name = this.nameTextBox.value; this.model.isEnabled = this.enabledCheckBox.checked; - + this.model.jobId = this.jobId; + this.model.jobName = this.jobName; this.model.alertType = this.getDropdownValue(this.typeDropDown); let databaseName = this.getDropdownValue(this.databaseDropDown); this.model.databaseName = (databaseName !== AlertDialog.AllDatabases) ? databaseName : undefined; diff --git a/extensions/agent/src/dialogs/jobDialog.ts b/extensions/agent/src/dialogs/jobDialog.ts index bf3523daf1..bbbce0f4a8 100644 --- a/extensions/agent/src/dialogs/jobDialog.ts +++ b/extensions/agent/src/dialogs/jobDialog.ts @@ -11,6 +11,7 @@ import { PickScheduleDialog } from './pickScheduleDialog'; import { AlertDialog } from './alertDialog'; import { AgentDialog } from './agentDialog'; import { AgentUtils } from '../agentUtils'; +import { JobStepData } from '../data/jobStepData'; const localize = nls.loadMessageBundle(); @@ -110,11 +111,19 @@ export class JobDialog extends AgentDialog { private newAlertButton: sqlops.ButtonComponent; private isEdit: boolean = false; + // Job objects + private steps: sqlops.AgentJobStepInfo[]; + private schedules: sqlops.AgentJobScheduleInfo[]; + private alerts: sqlops.AgentAlertInfo[] = []; + constructor(ownerUri: string, jobInfo: sqlops.AgentJobInfo = undefined) { super( ownerUri, new JobData(ownerUri, jobInfo), jobInfo ? JobDialog.EditDialogTitle : JobDialog.CreateDialogTitle); + this.steps = this.model.jobSteps ? this.model.jobSteps : []; + this.schedules = this.model.jobSchedules ? this.model.jobSchedules : []; + this.alerts = this.model.alerts ? this.model.alerts : []; this.isEdit = jobInfo ? true : false; } @@ -198,12 +207,7 @@ export class JobDialog extends AgentDialog { private initializeStepsTab() { this.stepsTab.registerContent(async view => { - let previewTag = view.modelBuilder.text() - .withProperties({ - value: 'Feature Preview' - }).component(); - let steps = this.model.jobSteps ? this.model.jobSteps : []; - let data = this.convertStepsToData(steps); + let data = this.steps ? this.convertStepsToData(this.steps) : []; this.stepsTable = view.modelBuilder.table() .withProperties({ columns: [ @@ -237,13 +241,11 @@ export class JobDialog extends AgentDialog { width: 80 }).component(); - let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model); + let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, null, true); stepDialog.onSuccess((step) => { - if (!this.model.jobSteps) { - this.model.jobSteps = []; - } - this.model.jobSteps.push(step); - this.stepsTable.data = this.convertStepsToData(this.model.jobSteps); + let stepInfo = JobStepData.convertToAgentJobStepInfo(step); + this.steps.push(stepInfo); + this.stepsTable.data = this.convertStepsToData(this.steps); }); this.newStepButton.onDidClick((e)=>{ if (this.nameTextBox.value && this.nameTextBox.value.length > 0) { @@ -277,7 +279,7 @@ export class JobDialog extends AgentDialog { this.deleteStepButton.enabled = true; this.editStepButton.enabled = true; this.editStepButton.onDidClick(() => { - let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, stepData); + let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, stepData, true); stepDialog.openDialog(); }); @@ -287,7 +289,6 @@ export class JobDialog extends AgentDialog { agentService.deleteJobStep(this.ownerUri, stepData).then((result) => { if (result && result.success) { delete steps[rowNumber]; - this.model.jobSteps = steps; let data = this.convertStepsToData(steps); this.stepsTable.data = data; } @@ -299,10 +300,6 @@ export class JobDialog extends AgentDialog { let formModel = view.modelBuilder.formContainer() .withFormItems([{ - component: previewTag, - title: '' - }, - { component: this.stepsTable, title: this.JobStepsTopLabelString, actions: [this.moveStepUpButton, this.moveStepDownButton, this.newStepButton, this.editStepButton, this.deleteStepButton] @@ -313,10 +310,6 @@ export class JobDialog extends AgentDialog { private initializeAlertsTab() { this.alertsTab.registerContent(async view => { - let previewTag = view.modelBuilder.text() - .withProperties({ - value: 'Feature Preview' - }).component(); let alerts = this.model.alerts ? this.model.alerts : []; let data = this.convertAlertsToData(alerts); this.alertsTable = view.modelBuilder.table() @@ -327,7 +320,7 @@ export class JobDialog extends AgentDialog { this.AlertTypeLabelString ], data: data, - height: 430, + height: 750, width: 400 }).component(); @@ -336,18 +329,24 @@ export class JobDialog extends AgentDialog { width: 80 }).component(); - this.newAlertButton.onDidClick((e)=>{ - let alertDialog = new AlertDialog(this.model.ownerUri, null, []); - alertDialog.onSuccess((dialogModel) => { - }); - alertDialog.openDialog(); + let alertDialog = new AlertDialog(this.model.ownerUri, this.model, null, true); + alertDialog.onSuccess((alert) => { + let alertInfo = alert.toAgentAlertInfo(); + this.alerts.push(alertInfo); + this.alertsTable.data = this.convertAlertsToData(this.alerts); + }); + this.newAlertButton.onDidClick(()=>{ + if (this.nameTextBox.value && this.nameTextBox.value.length > 0) { + alertDialog.jobId = this.model.jobId; + alertDialog.jobName = this.model.name ? this.model.name : this.nameTextBox.value; + alertDialog.openDialog(); + } else { + this.dialog.message = { text: this.BlankJobNameErrorText }; + } }); let formModel = view.modelBuilder.formContainer() .withFormItems([{ - component: previewTag, - title: '' - }, { component: this.alertsTable, title: this.AlertsTopLabelString, actions: [this.newAlertButton] @@ -380,8 +379,11 @@ export class JobDialog extends AgentDialog { pickScheduleDialog.onSuccess((dialogModel) => { let selectedSchedule = dialogModel.selectedSchedule; if (selectedSchedule) { - selectedSchedule.jobName = this.model.name; - this.model.addJobSchedule(selectedSchedule); + let existingSchedule = this.schedules.find(item => item.name === selectedSchedule.name); + if (!existingSchedule) { + selectedSchedule.jobName = this.model.name ? this.model.name : this.nameTextBox.value; + this.schedules.push(selectedSchedule); + } this.populateScheduleTable(); } }); @@ -402,8 +404,7 @@ export class JobDialog extends AgentDialog { } private populateScheduleTable() { - let schedules = this.model.jobSchedules ? this.model.jobSchedules : []; - let data = this.convertSchedulesToData(schedules); + let data = this.convertSchedulesToData(this.schedules); if (data.length > 0) { this.schedulesTable.data = data; this.schedulesTable.height = 750; @@ -566,5 +567,17 @@ export class JobDialog extends AgentDialog { this.model.pageLevel = this.getActualConditionValue(this.pagerCheckBox, this.pagerConditionDropdown); this.model.eventLogLevel = this.getActualConditionValue(this.eventLogCheckBox, this.eventLogConditionDropdown); this.model.deleteLevel = this.getActualConditionValue(this.deleteJobCheckBox, this.deleteJobConditionDropdown); + if (!this.model.jobSteps) { + this.model.jobSteps = []; + } + this.model.jobSteps = this.steps; + if (!this.model.jobSchedules) { + this.model.jobSchedules = []; + } + this.model.jobSchedules = this.schedules; + if (!this.model.alerts) { + this.model.alerts = []; + } + this.model.alerts = this.alerts; } } \ No newline at end of file diff --git a/extensions/agent/src/dialogs/jobStepDialog.ts b/extensions/agent/src/dialogs/jobStepDialog.ts index da0ec4028b..614f49794c 100644 --- a/extensions/agent/src/dialogs/jobStepDialog.ts +++ b/extensions/agent/src/dialogs/jobStepDialog.ts @@ -118,9 +118,10 @@ export class JobStepDialog extends AgentDialog { server: string, jobModel: JobData, jobStepInfo?: sqlops.AgentJobStepInfo, + viaJobDialog: boolean = false ) { super(ownerUri, - jobStepInfo ? JobStepData.convertToJobStepData(jobStepInfo, jobModel) : new JobStepData(ownerUri, jobModel), + jobStepInfo ? JobStepData.convertToJobStepData(jobStepInfo, jobModel) : new JobStepData(ownerUri, jobModel, viaJobDialog), jobStepInfo ? JobStepDialog.EditDialogTitle : JobStepDialog.NewDialogTitle); this.stepId = jobStepInfo ? jobStepInfo.id : jobModel.jobSteps ? diff --git a/extensions/agent/src/mainController.ts b/extensions/agent/src/mainController.ts index af10fa01be..ce1ff93608 100644 --- a/extensions/agent/src/mainController.ts +++ b/extensions/agent/src/mainController.ts @@ -14,6 +14,7 @@ import { ProxyDialog } from './dialogs/proxyDialog'; import { JobStepDialog } from './dialogs/jobStepDialog'; import { PickScheduleDialog } from './dialogs/pickScheduleDialog'; import { JobData } from './data/jobData'; +import { AgentUtils } from './agentUtils'; const localize = nls.loadMessageBundle(); @@ -41,17 +42,23 @@ export class MainController { let dialog = new JobDialog(ownerUri, jobInfo); dialog.openDialog(); }); - vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobData: JobData, jobStepInfo: sqlops.AgentJobStepInfo) => { - let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo); - dialog.openDialog(); + vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobInfo: sqlops.AgentJobInfo, jobStepInfo: sqlops.AgentJobStepInfo) => { + AgentUtils.getAgentService().then((agentService) => { + let jobData: JobData = new JobData(ownerUri, jobInfo, agentService); + let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo, false); + dialog.openDialog(); + }); }); vscode.commands.registerCommand('agent.openPickScheduleDialog', (ownerUri: string, jobName: string) => { let dialog = new PickScheduleDialog(ownerUri, jobName); dialog.showDialog(); }); - vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, alertInfo: sqlops.AgentAlertInfo, jobs: string[]) => { - let dialog = new AlertDialog(ownerUri, alertInfo, jobs); - dialog.openDialog(); + vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, jobInfo: sqlops.AgentJobInfo, alertInfo: sqlops.AgentAlertInfo) => { + AgentUtils.getAgentService().then((agentService) => { + let jobData: JobData = new JobData(ownerUri, jobInfo, agentService); + let dialog = new AlertDialog(ownerUri, jobData, alertInfo, false); + dialog.openDialog(); + }); }); vscode.commands.registerCommand('agent.openOperatorDialog', (ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo) => { let dialog = new OperatorDialog(ownerUri, operatorInfo); diff --git a/extensions/import/package.json b/extensions/import/package.json index fc7932a503..871078cb7e 100644 --- a/extensions/import/package.json +++ b/extensions/import/package.json @@ -2,7 +2,7 @@ "name": "import", "displayName": "SQL Server Import", "description": "SQL Server Import for Azure Data Studio supports importing CSV or JSON files into SQL Server.", - "version": "0.3.0", + "version": "0.4.0", "publisher": "Microsoft", "preview": true, "engines": { @@ -42,33 +42,6 @@ "mac": "ctrl+i" } ], - "dashboard.tabs": [ - { - "id": "flat-file-import", - "title": "Flat File Import", - "description": "The flat file importer.", - "container": { - "flat-file-import-container": {} - } - } - ], - "dashboard.containers": [ - { - "id": "flat-file-import-container", - "container": { - "widgets-container": [ - { - "name": "Tasks", - "widget": { - "tasks-widget": [ - "flatFileImport.start" - ] - } - } - ] - } - } - ], "menus": { "objectExplorer/item/context": [ { diff --git a/extensions/import/src/wizard/flatFileWizard.ts b/extensions/import/src/wizard/flatFileWizard.ts index 386740028a..e0062eb271 100644 --- a/extensions/import/src/wizard/flatFileWizard.ts +++ b/extensions/import/src/wizard/flatFileWizard.ts @@ -31,7 +31,7 @@ export class FlatFileWizard { public async start(p: any, ...args: any[]) { let model = {}; - let profile = p.connectionProfile; + let profile = p ? p.connectionProfile : null; if (profile) { model.serverId = profile.id; model.database = profile.databaseName; diff --git a/extensions/mssql/snippets/mssql.json b/extensions/mssql/snippets/mssql.json index aa4ba3852d..6d1a64275a 100644 --- a/extensions/mssql/snippets/mssql.json +++ b/extensions/mssql/snippets/mssql.json @@ -42,18 +42,18 @@ "Create a new Table": { "prefix": "sqlCreateTable", "body": [ - "-- Create a new table called '[${1:TableName}]' in schema '[${2:SchemaName}]' in database '[${3:DatabaseName}]'", + "-- Create a new table called '[${1:TableName}]' in schema '[${2:dbo}]'", "-- Drop the table if it already exists", - "IF OBJECT_ID('[${3:DatabaseName}].[${2:SchemaName}].[${1:TableName}]', 'U') IS NOT NULL", - "DROP TABLE [${3:DatabaseName}].[${2:SchemaName}].[${1:TableName}]", + "IF OBJECT_ID('[${2:dbo}].[${1:TableName}]', 'U') IS NOT NULL", + "DROP TABLE [${2:dbo}].[${1:TableName}]", "GO", - "-- Create the table in the specified database and schema", - "CREATE TABLE [${3:DatabaseName}].[${2:SchemaName}].[${1:TableName}]", + "-- Create the table in the specified schema", + "CREATE TABLE [${2:dbo}].[${1:TableName}]", "(", - "\t[${4:ColumnName}]Id INT NOT NULL PRIMARY KEY, -- Primary Key column", - "\t[${5:ColumnName1}] [NVARCHAR](50) NOT NULL,", - "\t[${6:ColumnName2}] [NVARCHAR](50) NOT NULL", - "\t-- Specify more columns here", + "\t[${3:Id}] INT NOT NULL PRIMARY KEY, -- Primary Key column", + "\t[${4:ColumnName2}] ${5:NVARCHAR(50)} NOT NULL,", + "\t[${6:ColumnName3}] ${7:NVARCHAR(50)} NOT NULL", + "\t$0-- Specify more columns here", ");", "GO" ], @@ -64,10 +64,10 @@ "Drop a Table": { "prefix": "sqlDropTable", "body": [ - "-- Drop a table called '${3:TableName}' in schema '${2:SchemaName}' in Database '${1:DatabaseName}'", + "-- Drop a table called '${1:TableName}' in schema '${2:dbo}'", "-- Drop the table if it already exists", - "IF OBJECT_ID('[${1:DatabaseName}].[${2:SchemaName}].[${3:TableName}]', 'U') IS NOT NULL", - "DROP TABLE [${1:DatabaseName}].[${2:SchemaName}].[${3:TableName}]", + "IF OBJECT_ID('[${2:dbo}].[${1:TableName}]', 'U') IS NOT NULL", + "DROP TABLE [${2:dbo}].[${1:TableName}]", "GO" ], "description": "Drop a Table" @@ -76,9 +76,9 @@ "Add a new column to a Table": { "prefix": "sqlAddColumn", "body": [ - "-- Add a new column '[${1:NewColumnName}]' to table '[${2:TableName}]' in schema '[${3:SchemaName}]' in database '[${4:DatabaseName}]'", - "ALTER TABLE [${4:DatabaseName}].[${3:SchemaName}].[${2:TableName}]", - "\tADD [${1:NewColumnName}] /*new_column_name*/ ${5:int} /*new_column_datatype*/ ${6:NULL} /*new_column_nullability*/", + "-- Add a new column '[${1:NewColumnName}]' to table '[${2:TableName}]' in schema '[${3:dbo}]'", + "ALTER TABLE [${3:dbo}].[${2:TableName}]", + "\tADD [${1:NewColumnName}] /*new_column_name*/ ${4:int} /*new_column_datatype*/ ${5:NULL} /*new_column_nullability*/", "GO" ], "description": "Add a new column to a Table" @@ -87,8 +87,8 @@ "Drop a column from a Table": { "prefix": "sqlDropColumn", "body": [ - "-- Drop '[${1:ColumnName}]' from table '[${2:TableName}]' in schema '[${3:SchemaName}]' in database '[${4:DatabaseName}]'", - "ALTER TABLE [${4:DatabaseName}].[${3:SchemaName}].[${2:TableName}]", + "-- Drop '[${1:ColumnName}]' from table '[${2:TableName}]' in schema '[${3:dbo}]'", + "ALTER TABLE [${3:dbo}].[${2:TableName}]", "\tDROP COLUMN [${1:ColumnName}]", "GO" ], @@ -98,9 +98,9 @@ "Select rows from a Table or a View": { "prefix": "sqlSelect", "body": [ - "-- Select rows from a Table or View '[${1:TableOrViewName}]' in schema '[${2:SchemaName}]' in database '[${3:DatabaseName}]'", - "SELECT * FROM [${3:DatabaseName}].[${2:SchemaName}].[${1:TableOrViewName}]", - "WHERE ${4:/* add search conditions here */}", + "-- Select rows from a Table or View '[${1:TableOrViewName}]' in schema '[${2:dbo}]'", + "SELECT * FROM [${2:dbo}].[${1:TableOrViewName}]", + "WHERE ${3:/* add search conditions here */}", "GO" ], "description": "Select rows from a Table or a View" @@ -109,17 +109,17 @@ "Insert rows into a Table": { "prefix": "sqlInsertRows", "body": [ - "-- Insert rows into table '${1:TableName}' in schema '[${2:SchemaName}]' in database '[${3:DatabaseName}]'", - "INSERT INTO [${3:DatabaseName}].[${2:SchemaName}].[${1:TableName}]", + "-- Insert rows into table '${1:TableName}' in schema '[${2:dbo}]'", + "INSERT INTO [${2:dbo}].[${1:TableName}]", "( -- Columns to insert data into", - " ${4:[ColumnName1], [ColumnName2], [ColumnName3]}", + " ${3:[ColumnName1], [ColumnName2], [ColumnName3]}", ")", "VALUES", "( -- First row: values for the columns in the list above", - " ${5:ColumnValue1, ColumnValue2, ColumnValue3}", + " ${4:ColumnValue1, ColumnValue2, ColumnValue3}", "),", "( -- Second row: values for the columns in the list above", - " ${6:ColumnValue1, ColumnValue2, ColumnValue3}", + " ${5:ColumnValue1, ColumnValue2, ColumnValue3}", ")", "-- Add more rows here", "GO" @@ -130,9 +130,9 @@ "Delete rows from a Table": { "prefix": "sqlDeleteRows", "body": [ - "-- Delete rows from table '[${1:TableName}]' in schema '[${2:SchemaName}]' in database '[${3:DatabaseName}]'", - "DELETE FROM [${3:DatabaseName}].[${2:SchemaName}].[${1:TableName}]", - "WHERE ${4:/* add search conditions here */}", + "-- Delete rows from table '[${1:TableName}]' in schema '[${2:dbo}]'", + "DELETE FROM [${2:dbo}].[${1:TableName}]", + "WHERE ${3:/* add search conditions here */}", "GO" ], "description": "Delete rows from a Table" @@ -141,13 +141,13 @@ "Update rows in a Table": { "prefix": "sqlUpdateRows", "body": [ - "-- Update rows in table '[${1:TableName}]' in schema '[${2:SchemaName}]' in database '[${3:DatabaseName}]'", - "UPDATE [${3:DatabaseName}].[${2:SchemaName}].[${1:TableName}]", + "-- Update rows in table '[${1:TableName}]' in schema '[${2:dbo}]'", + "UPDATE [${2:dbo}].[${1:TableName}]", "SET", - "\t[${4:ColumnName1}] = ${5:ColumnValue1},", - "\t[${6:ColumnName2}] = ${7:ColumnValue2}", + "\t[${3:ColumnName1}] = ${4:ColumnValue1},", + "\t[${5:ColumnName2}] = ${6:ColumnValue2}", "\t-- Add more columns and values here", - "WHERE ${8:/* add search conditions here */}", + "WHERE ${7:/* add search conditions here */}", "GO" ], "description": "Update rows in a Table" @@ -156,27 +156,27 @@ "Create a stored procedure": { "prefix": "sqlCreateStoredProc", "body": [ - "-- Create a new stored procedure called '${1:StoredProcedureName}' in schema '${2:SchemaName}'", + "-- Create a new stored procedure called '${1:StoredProcedureName}' in schema '${2:dbo}'", "-- Drop the stored procedure if it already exists", "IF EXISTS (", "SELECT *", "\tFROM INFORMATION_SCHEMA.ROUTINES", - "WHERE SPECIFIC_SCHEMA = N'${2:SchemaName}'", + "WHERE SPECIFIC_SCHEMA = N'${2:dbo}'", "\tAND SPECIFIC_NAME = N'${1:StoredProcedureName}'", ")", - "DROP PROCEDURE ${2:SchemaName}.${1:StoredProcedureName}", + "DROP PROCEDURE ${2:dbo}.${1:StoredProcedureName}", "GO", "-- Create the stored procedure in the specified schema", - "CREATE PROCEDURE ${2:SchemaName}.${1:StoredProcedureName}", - "\t$3@param1 /*parameter name*/ int /*datatype_for_param1*/ = 0, /*default_value_for_param1*/", - "\t$4@param2 /*parameter name*/ int /*datatype_for_param1*/ = 0 /*default_value_for_param2*/", + "CREATE PROCEDURE ${2:dbo}.${1:StoredProcedureName}", + "\t$3@param1 /*parameter name*/ $4int /*datatype_for_param1*/ = 0, /*default_value_for_param1*/", + "\t$5@param2 /*parameter name*/ $6int /*datatype_for_param1*/ = 0 /*default_value_for_param2*/", "-- add more stored procedure parameters here", "AS", "\t-- body of the stored procedure", "\tSELECT @param1, @param2", "GO", "-- example to execute the stored procedure we just created", - "EXECUTE ${2:SchemaName}.${1:StoredProcedureName} 1 /*value_for_param1*/, 2 /*value_for_param2*/", + "EXECUTE ${2:dbo}.${1:StoredProcedureName} 1 /*value_for_param1*/, 2 /*value_for_param2*/", "GO" ], "description": "Create a stored procedure" @@ -185,14 +185,14 @@ "Drop a stored procedure": { "prefix": "sqlDropStoredProc", "body": [ - "-- Drop the stored procedure called '${1:StoredProcedureName}' in schema '${2:SchemaName}'", + "-- Drop the stored procedure called '${1:StoredProcedureName}' in schema '${2:dbo}'", "IF EXISTS (", "SELECT *", "\tFROM INFORMATION_SCHEMA.ROUTINES", - "WHERE SPECIFIC_SCHEMA = N'${2:SchemaName}'", + "WHERE SPECIFIC_SCHEMA = N'${2:dbo}'", "\tAND SPECIFIC_NAME = N'${1:StoredProcedureName}'", ")", - "DROP PROCEDURE ${2:SchemaName}.${1:StoredProcedureName}", + "DROP PROCEDURE ${2:dbo}.${1:StoredProcedureName}", "GO" ], "description": "Drop a stored procedure" @@ -241,7 +241,7 @@ "Declare a cursor": { "prefix": "sqlCursor", "body": [ - "-- Declare a cursor for a Table or a View '${1:TableOrViewName}' in schema '${2:SchemaName}'", + "-- Declare a cursor for a Table or a View '${1:TableOrViewName}' in schema '${2:dbo}'", "DECLARE @ColumnName1 NVARCHAR(50), @ColumnName2 NVARCHAR(50)", "", "DECLARE db_cursor CURSOR FOR", @@ -304,8 +304,8 @@ "prefix": "sqlCreateIndex", "body": [ "-- Create a nonclustered index with or without a unique constraint", - "-- Or create a clustered index on table '[${1:TableName}]' in schema '[${2:SchemaName}]' in database '[${3:DatabaseName}]'", - "CREATE ${5:/*UNIQUE or CLUSTERED*/} INDEX IX_${4:IndexName} ON [${3:DatabaseName}].[${2:SchemaName}].[${1:TableName}] ([${6:ColumnName1}] DESC /*Change sort order as needed*/", + "-- Or create a clustered index on table '[${1:TableName}]' in schema '[${2:dbo}]' in database '[${3:DatabaseName}]'", + "CREATE ${5:/*UNIQUE or CLUSTERED*/} INDEX IX_${4:IndexName} ON [${3:DatabaseName}].[${2:dbo}].[${1:TableName}] ([${6:ColumnName1}] DESC /*Change sort order as needed*/", "GO" ], "description": "Create a new Index" @@ -319,13 +319,13 @@ "IF OBJECT_ID('tempDB..#${1:TableName}', 'U') IS NOT NULL", "DROP TABLE #${1:TableName}", "GO", - "-- Create the temporary table from a physical table called '${4:TableName}' in schema '${3:SchemaName}' in database '${2:DatabaseName}'", + "-- Create the temporary table from a physical table called '${4:TableName}' in schema '${3:dbo}' in database '${2:DatabaseName}'", "SELECT *", "INTO #${1:TableName}", - "FROM [${2:DatabaseName}].[${3:[SchemaName}].[${4:TableName}]", + "FROM [${2:DatabaseName}].[${3:[dbo}].[${4:TableName}]", "WHERE ${5:/* add search conditions here */}" ], "description": "Create a new Temporary Table" - }, + } } diff --git a/extensions/mssql/src/config.json b/extensions/mssql/src/config.json index 1e8bb179f7..f4b626b481 100644 --- a/extensions/mssql/src/config.json +++ b/extensions/mssql/src/config.json @@ -1,6 +1,6 @@ { "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", - "version": "1.5.0-alpha.48", + "version": "1.5.0-alpha.52", "downloadFileNames": { "Windows_86": "win-x86-netcoreapp2.2.zip", "Windows_64": "win-x64-netcoreapp2.2.zip", diff --git a/extensions/profiler/package.json b/extensions/profiler/package.json index 3924d69b70..f2cdd86357 100644 --- a/extensions/profiler/package.json +++ b/extensions/profiler/package.json @@ -2,7 +2,7 @@ "name": "profiler", "displayName": "SQL Server Profiler", "description": "SQL Server Profiler for Azure Data Studio", - "version": "0.2.0", + "version": "0.3.0", "publisher": "Microsoft", "preview": true, "license": "https://raw.githubusercontent.com/Microsoft/azuredatastudio/master/LICENSE.txt", diff --git a/extensions/theme-carbon/themes/dark_carbon.json b/extensions/theme-carbon/themes/dark_carbon.json index 1f0285cc14..674c8b176d 100644 --- a/extensions/theme-carbon/themes/dark_carbon.json +++ b/extensions/theme-carbon/themes/dark_carbon.json @@ -4,66 +4,69 @@ "type": "dark", "colors": { - // base - "foreground": "#fffffe", - "focusBorder": "#0E639C", + // base + "foreground": "#fffffe", + "focusBorder": "#0078d7", "selection.background": "#3062d6", - //text colors - "textLinkForeground": "#30B4FF", - "textLinkActiveForeground": "#30B4FF", + //text colors + "textLinkForeground": "#30b4ff", + "textLinkActiveForeground": "#30b4ff", - //Button control - "button.background": "#00BCF2", - "button.foreground": "#212121", - "button.hoverBackground": "#0099BC", + //Button control + "button.background": "#0078d7cc", + "button.foreground": "#ffffff", + "button.hoverBackground": "#0078d7", - // TODO add support for these - // "button.secondaryBackground": "#c8c8c8", - // "button.secondaryHoverBackground": "#a6a6a6", - // "button.secondaryForeground": "#333333", - // "button.disabledBackground": "#444444" , - // "button.disabledForeground": "#888888" , + // TODO add support for these + // "button.secondaryBackground": "#c8c8c8", + // "button.secondaryHoverBackground": "#a6a6a6", + // "button.secondaryForeground": "#333333", + // "button.disabledBackground": "#444444" , + // "button.disabledForeground": "#888888" , - //Dropdown Control - "dropdown.background": "#212121", - "dropdown.foreground": "#fffffe", - "dropdown.border": "#888888", + //Checkbox + "checkbox.disabled.foreground": "#888888", - //Input Control - "input.background": "#212121", + //Dropdown Control + "dropdown.background": "#212121", + "dropdown.foreground": "#fffffe", + "dropdown.border": "#888888", + + //Input Control + "input.background": "#212121", "input.border": "#888888", "input.disabled.background": "#444444", "input.disabled.foreground": "#888888", - "inputOption.activeBorder": "#007ACC", - "input.placeholderForeground": "#888888", - "inputValidation.errorBackground": "#D02E00", - "inputValidation.errorBorder": "#D02E00", + "inputOption.activeBorder": "#0078d7", + "input.placeholderForeground": "#888888", + "inputValidation.errorBackground": "#b62e00", + "inputValidation.errorBorder": "#b62e00", - //List and trees - "list.activeSelectionBackground": "#3062d6", - "list.hoverBackground": "#444444", - "pickerGroup.border": "#00BCF2", + //List and trees + "list.activeSelectionBackground": "#3062d6", + "list.hoverBackground": "#444444", + "pickerGroup.border": "#0078d7", "activityBar.background": "#444444", "sideBar.background": "#333333", - "sideBarTitle.foreground": "#BBBBBB", - "input.placeholderForeground": "#A6A6A6", - "editorGroupHeader.tabsBackground": "#444444", - "editor.background": "#212121", - "editor.foreground": "#ffffff", - "editorWidget.background": "#444444", - "editorLink.activeForeground": "#30B4FF", - "editorGroup.border": "#333333", - "editorGroup.background": "#212121", - "editorIndentGuide.activeBackground": "#707070", - "tab.activeBackground": "#212121", - "tab.activeForeground": "#ffffff", - "tab.inactiveBackground": "#444444", - "tab.inactiveForeground": "#b6b6b6", + "sideBarTitle.foreground": "#bbbbbb", + "input.placeholderForeground": "#a6a6a6", + "editorGroupHeader.tabsBackground": "#444444", + "editor.background": "#212121", + "editor.foreground": "#ffffff", + "editorWidget.background": "#444444", + "editorLink.activeForeground": "#30b4ff", + "editorGroup.border": "#333333", + "editorGroup.background": "#212121", + "editorIndentGuide.activeBackground": "#707070", + "tab.activeBackground": "#212121", + "tab.activeForeground": "#ffffff", + "tab.inactiveBackground": "#444444", + "tab.inactiveForeground": "#b6b6b6", "tab.border": "#3c3c3c", - "panel.background": "#212121", - "panel.border": "#515151", - "panelTitle.activeForeground": "#ffffff", + "panel.background": "#212121", + "panel.border": "#515151", + "panelTitle.activeForeground": "#ffffff", "panelTitle.inactiveForeground": "#888888" }, "tokenColors": [ diff --git a/extensions/theme-carbon/themes/light_carbon.json b/extensions/theme-carbon/themes/light_carbon.json index fa2dc6183c..4db0a032b2 100644 --- a/extensions/theme-carbon/themes/light_carbon.json +++ b/extensions/theme-carbon/themes/light_carbon.json @@ -5,18 +5,18 @@ "colors": { // base "foreground": "#4a4a4a", - "focusBorder": "#00BCF2", - "selection.background": "#C9D0D9", + "focusBorder": "#0078d7", + "selection.background": "#c9d0d9", "widget.shadow": "#666666", // text colors - "textLinkForeground": "#3062D6", - "textLinkActiveForeground": "#3062D6", + "textLinkForeground": "#3062d6", + "textLinkActiveForeground": "#3062d6", //Button control - "button.background": "#00BCF2", - "button.foreground": "#212121", - "button.hoverBackground": "#0099BC", + "button.background": "#0078d7cc", + "button.foreground": "#ffffff", + "button.hoverBackground": "#0078d7", // TODO add support for these // "button.secondaryBackground": "#c8c8c8", @@ -25,35 +25,38 @@ // "button.disabledBackground": "#eaeaea", // "button.disabledForeground": "#888888", + //Checkbox + "checkbox.disabled.foreground": "#888888", + //Dropdown Control - "dropdown.background": "#fffffe", + "dropdown.background": "#ffffff", "dropdown.foreground": "#4a4a4a", - "dropdown.border": "#C8C8C8", + "dropdown.border": "#c8c8c8", //badge "badge.background": "#777777", "badge.foreground": "#ffffff", //Input Control - "input.background": "#fffffe", + "input.background": "#ffffff", "input.border": "#c8c8c8", "input.disabled.background": "#dcdcdc", "input.disabled.foreground": "#888888", "inputOption.activeBorder": "#666666", "input.placeholderForeground": "#767676", "inputValidation.errorBackground": "#ffeaea", - "inputValidation.errorBorder": "#f1897f", + "inputValidation.errorBorder": "#b62e00", //List and tree "list.activeSelectionBackground": "#3062d6", "list.hoverBackground": "#dcdcdc", - "pickerGroup.border": "#00BCF2", + "pickerGroup.border": "#0078d7", // Workbench: Activity Bar "activityBar.background": "#212121", // Workbench: Side Bar - "sideBar.background": "#EAEAEA", + "sideBar.background": "#eaeaea", "editorGroupHeader.tabsBackground": "#f4f4f4", "editor.background": "#fffffe", "editor.foreground": "#212121", @@ -64,15 +67,15 @@ "editorIndentGuide.activeBackground": "#939393", // Workbench: Tabs - "tab.activeBackground": "#FFFFFE", - "tab.activeForeground": "#4A4A4A", + "tab.activeBackground": "#ffffff", + "tab.activeForeground": "#4a4a4a", "tab.inactiveBackground": "#f4f4f4", "tab.inactiveForeground": "#707070", - "tab.border": "#EAEAEA", + "tab.border": "#eaeaea", "tab.unfocusedInactiveForeground": "#888888", "tab.unfocusedActiveForeground": "#212121", - "panel.background": "#FFFFFE", - "panel.border": "#C8C8C8", + "panel.background": "#ffffff", + "panel.border": "#c8c8c8", "panelTitle.activeForeground": "#212121", "panelTitle.inactiveForeground": "#757575" }, diff --git a/package.json b/package.json index 559b3e90da..3abb6216c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "azuredatastudio", - "version": "1.2.3", + "version": "1.2.4", "distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee", "author": { "name": "Microsoft Corporation" diff --git a/src/sql/base/browser/ui/checkbox/checkbox.ts b/src/sql/base/browser/ui/checkbox/checkbox.ts index f4a3d36dba..00064391c7 100644 --- a/src/sql/base/browser/ui/checkbox/checkbox.ts +++ b/src/sql/base/browser/ui/checkbox/checkbox.ts @@ -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(); public readonly onChange: Event = 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'; + } } diff --git a/src/sql/base/browser/ui/modal/media/modal.css b/src/sql/base/browser/ui/modal/media/modal.css index f639771d95..abe53a1d80 100644 --- a/src/sql/base/browser/ui/modal/media/modal.css +++ b/src/sql/base/browser/ui/modal/media/modal.css @@ -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; } diff --git a/src/sql/base/browser/ui/modal/modal.ts b/src/sql/base/browser/ui/modal/modal.ts index 44f8a153d3..016e9968ce 100644 --- a/src/sql/base/browser/ui/modal/modal.ts +++ b/src/sql/base/browser/ui/modal/modal.ts @@ -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>(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'); diff --git a/src/sql/base/browser/ui/splitview/splitview.css b/src/sql/base/browser/ui/splitview/splitview.css index 763146127e..312f1519dc 100644 --- a/src/sql/base/browser/ui/splitview/splitview.css +++ b/src/sql/base/browser/ui/splitview/splitview.css @@ -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; } \ No newline at end of file diff --git a/src/sql/common/theme/colors.ts b/src/sql/common/theme/colors.ts index eb42ca596d..0e9cd3638b 100644 --- a/src/sql/common/theme/colors.ts +++ b/src/sql/common/theme/colors.ts @@ -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")); diff --git a/src/sql/common/theme/styler.ts b/src/sql/common/theme/styler.ts index df2b8e936f..d0a7936576 100644 --- a/src/sql/common/theme/styler.ts +++ b/src/sql/common/theme/styler.ts @@ -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); +} diff --git a/src/sql/parts/commandLine/common/commandLine.ts b/src/sql/parts/commandLine/common/commandLine.ts new file mode 100644 index 0000000000..4290a6308b --- /dev/null +++ b/src/sql/parts/commandLine/common/commandLine.ts @@ -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('commandLineService'); \ No newline at end of file diff --git a/src/sql/parts/commandLine/common/commandLineService.ts b/src/sql/parts/commandLine/common/commandLineService.ts new file mode 100644 index 0000000000..e9d9c53935 --- /dev/null +++ b/src/sql/parts/commandLine/common/commandLineService.ts @@ -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(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(() => { }); + } + } +} \ No newline at end of file diff --git a/src/sql/parts/connection/common/connectionManagementService.ts b/src/sql/parts/connection/common/connectionManagementService.ts index 80f466fa9e..2d468afe31 100644 --- a/src/sql/parts/connection/common/connectionManagementService.ts +++ b/src/sql/parts/connection/common/connectionManagementService.ts @@ -77,7 +77,6 @@ export class ConnectionManagementService extends Disposable implements IConnecti private _onConnectRequestSent = new Emitter(); private _onConnectionChanged = new Emitter(); private _onLanguageFlavorChanged = new Emitter(); - 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(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 { + let self = this; return new Promise((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 { diff --git a/src/sql/parts/connection/connectionDialog/connectionWidget.ts b/src/sql/parts/connection/connectionDialog/connectionWidget.ts index 28880ade97..332f055a4e 100644 --- a/src/sql/parts/connection/connectionDialog/connectionWidget.ts +++ b/src/sql/parts/connection/connectionDialog/connectionWidget.ts @@ -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 diff --git a/src/sql/parts/disasterRecovery/backup/backup.component.ts b/src/sql/parts/disasterRecovery/backup/backup.component.ts index 909a0cc9fe..c6d5da6153 100644 --- a/src/sql/parts/disasterRecovery/backup/backup.component.ts +++ b/src/sql/parts/disasterRecovery/backup/backup.component.ts @@ -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()); diff --git a/src/sql/parts/disasterRecovery/backup/media/backupDialog.css b/src/sql/parts/disasterRecovery/backup/media/backupDialog.css index 8ec1f1c1c2..e338fcec04 100644 --- a/src/sql/parts/disasterRecovery/backup/media/backupDialog.css +++ b/src/sql/parts/disasterRecovery/backup/media/backupDialog.css @@ -17,7 +17,7 @@ } .backup-dialog { - height: calc(100% - 15px) + height: 100% } .backup-dialog .advanced-main-header { diff --git a/src/sql/parts/disasterRecovery/restore/restoreDialog.ts b/src/sql/parts/disasterRecovery/restore/restoreDialog.ts index 7b61e80710..39fc2a7757 100644 --- a/src/sql/parts/disasterRecovery/restore/restoreDialog.ts +++ b/src/sql/parts/disasterRecovery/restore/restoreDialog.ts @@ -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; } diff --git a/src/sql/parts/grid/load/css/qp.css b/src/sql/parts/grid/load/css/qp.css index e91aa988c3..48a9fee1ce 100644 --- a/src/sql/parts/grid/load/css/qp.css +++ b/src/sql/parts/grid/load/css/qp.css @@ -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 { diff --git a/src/sql/parts/jobManagement/common/jobActions.ts b/src/sql/parts/jobManagement/common/jobActions.ts index ef48595e69..1ec5c54fd9 100644 --- a/src/sql/parts/jobManagement/common/jobActions.ts +++ b/src/sql/parts/jobManagement/common/jobActions.ts @@ -219,14 +219,10 @@ export class NewStepAction extends Action { public run(context: JobHistoryComponent): TPromise { 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((resolve, reject) => { - resolve(this._commandService.executeCommand('agent.openNewStepDialog', ownerUri, jobName, server, stepId)); + resolve(this._commandService.executeCommand('agent.openNewStepDialog', ownerUri, server, jobInfo , null)); }); } } diff --git a/src/sql/parts/jobManagement/views/jobsView.component.ts b/src/sql/parts/jobManagement/views/jobsView.component.ts index e6e61ba465..ebaa2bb3bc 100644 --- a/src/sql/parts/jobManagement/views/jobsView.component.ts +++ b/src/sql/parts/jobManagement/views/jobsView.component.ts @@ -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; } diff --git a/src/sql/parts/modelComponents/checkbox.component.ts b/src/sql/parts/modelComponents/checkbox.component.ts index d8fe0ca504..b58744fd59 100644 --- a/src/sql/parts/modelComponents/checkbox.component.ts +++ b/src/sql/parts/modelComponents/checkbox.component.ts @@ -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)); } } diff --git a/src/sql/parts/query/editor/charting/chartView.ts b/src/sql/parts/query/editor/charting/chartView.ts index 728469c6be..0ae7471d44 100644 --- a/src/sql/parts/query/editor/charting/chartView.ts +++ b/src/sql/parts/query/editor/charting/chartView.ts @@ -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) { diff --git a/src/sql/parts/query/editor/charting/insights/graphInsight.ts b/src/sql/parts/query/editor/charting/insights/graphInsight.ts index b73ece6a38..d8cbe9e02c 100644 --- a/src/sql/parts/query/editor/charting/insights/graphInsight.ts +++ b/src/sql/parts/query/editor/charting/insights/graphInsight.ts @@ -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; let labels: Array; + let chartData: Array; 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 } diff --git a/src/sql/parts/queryPlan/queryPlan.ts b/src/sql/parts/queryPlan/queryPlan.ts index 390b600ebb..737daad64f 100644 --- a/src/sql/parts/queryPlan/queryPlan.ts +++ b/src/sql/parts/queryPlan/queryPlan.ts @@ -93,6 +93,10 @@ export class QueryPlan { QP.showPlan(this.container, this._xml, { jsTooltips: false }); + (this.container.querySelectorAll('div.qp-tt')).forEach(toolTip=>{ + toolTip.classList.add('monaco-editor'); + toolTip.classList.add('monaco-editor-hover'); + }); } public get xml(): string { diff --git a/src/sqltest/parts/commandLine/commandLineService.test.ts b/src/sqltest/parts/commandLine/commandLineService.test.ts new file mode 100644 index 0000000000..f00d529cc9 --- /dev/null +++ b/src/sqltest/parts/commandLine/commandLineService.test.ts @@ -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; + let queryEditorService : TypeMoq.Mock; + let editorService:TypeMoq.Mock; + let objectExplorerService : TypeMoq.Mock; + let connectionStore: TypeMoq.Mock; + + 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 + = TypeMoq.Mock.ofType(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 + = TypeMoq.Mock.ofType(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 + = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Strict); + + const environmentService : TypeMoq.Mock = TypeMoq.Mock.ofType(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((resolve, reject) => { reject('unused');})) + .verifiable(TypeMoq.Times.once()); + let service = getCommandLineService(connectionManagementService.object, environmentService.object, capabilitiesService); + service.processCommandLine(); + environmentService.verifyAll(); + connectionManagementService.verifyAll(); + done(); + }); +}); diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 2d07d986ee..3d5f67b51d 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -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('environmentService'); diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index dff9ea9cbc..bd15d92783 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -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}} } }; diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index bf7947d84b..88e643c316 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -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()));