mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-18 11:01:36 -05:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d67eca8bb | ||
|
|
74c4b7311e | ||
|
|
713c74adfd | ||
|
|
408a8a6f19 | ||
|
|
e1485e49d3 | ||
|
|
30b66934cd | ||
|
|
fd49c081c2 | ||
|
|
1327120024 | ||
|
|
d2b5043972 | ||
|
|
a0e55ea3fd | ||
|
|
1f32de29c1 | ||
|
|
12be06d682 | ||
|
|
27ca9b13f8 | ||
|
|
be45905830 | ||
|
|
05d0a89655 | ||
|
|
3ba575dcd0 | ||
|
|
3e200b7f0f | ||
|
|
cbce1f7008 | ||
|
|
e99101447e | ||
|
|
0ddb326e44 | ||
|
|
460446a15c | ||
|
|
4eea24997f | ||
|
|
0b1e9c7c66 | ||
|
|
d51a7a9eb7 | ||
|
|
0f0b959e14 | ||
|
|
b2ceb09e4d | ||
|
|
53953f5cda | ||
|
|
fbd5e819a2 | ||
|
|
bdc391d376 | ||
|
|
6b618fb121 |
@@ -13,6 +13,11 @@ import { IAgentDialogData, AgentDialogMode } from '../interfaces';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class AlertData implements IAgentDialogData {
|
||||
public static readonly AlertTypeSqlServerEventString: string = localize('alertData.DefaultAlertTypString', 'SQL Server event alert');
|
||||
public static readonly AlertTypePerformanceConditionString: string = localize('alertDialog.PerformanceCondition', 'SQL Server performance condition alert');
|
||||
public static readonly AlertTypeWmiEventString: string = localize('alertDialog.WmiEvent', 'WMI event alert');
|
||||
public static readonly DefaultAlertTypeString: string = AlertData.AlertTypeSqlServerEventString;
|
||||
|
||||
ownerUri: string;
|
||||
dialogMode: AgentDialogMode = AgentDialogMode.CREATE;
|
||||
id: number;
|
||||
@@ -23,7 +28,7 @@ export class AlertData implements IAgentDialogData {
|
||||
eventSource: string;
|
||||
hasNotification: number;
|
||||
includeEventDescription: string;
|
||||
isEnabled: boolean;
|
||||
isEnabled: boolean = true;
|
||||
jobId: string;
|
||||
jobName: string;
|
||||
lastOccurrenceDate: string;
|
||||
@@ -36,7 +41,7 @@ export class AlertData implements IAgentDialogData {
|
||||
databaseName: string;
|
||||
countResetDate: string;
|
||||
categoryName: string;
|
||||
alertType: string;
|
||||
alertType: string = AlertData.DefaultAlertTypeString;
|
||||
wmiEventNamespace: string;
|
||||
wmiEventQuery: string;
|
||||
|
||||
@@ -109,9 +114,19 @@ export class AlertData implements IAgentDialogData {
|
||||
databaseName: this.databaseName,
|
||||
countResetDate: this.countResetDate,
|
||||
categoryName: this.categoryName,
|
||||
alertType: sqlops.AlertType.sqlServerEvent, //this.alertType,
|
||||
alertType: AlertData.getAlertTypeFromString(this.alertType),
|
||||
wmiEventNamespace: this.wmiEventNamespace,
|
||||
wmiEventQuery: this.wmiEventQuery
|
||||
};
|
||||
}
|
||||
|
||||
private static getAlertTypeFromString(alertTypeString: string): sqlops.AlertType {
|
||||
if (alertTypeString === AlertData.AlertTypePerformanceConditionString) {
|
||||
return sqlops.AlertType.sqlServerPerformanceCondition;
|
||||
} else if (alertTypeString === AlertData.AlertTypeWmiEventString) {
|
||||
return sqlops.AlertType.wmiEvent;
|
||||
} else {
|
||||
return sqlops.AlertType.sqlServerEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,22 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { AgentUtils } from '../agentUtils';
|
||||
import { IAgentDialogData, AgentDialogMode } from '../interfaces';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class JobData implements IAgentDialogData {
|
||||
|
||||
private readonly JobCompletionActionCondition_Always: string = 'When the job completes';
|
||||
private readonly JobCompletionActionCondition_OnFailure: string = 'When the job fails';
|
||||
private readonly JobCompletionActionCondition_OnSuccess: string = 'When the job succeeds';
|
||||
private readonly JobCompletionActionCondition_Always: string = localize('jobData.whenJobCompletes', 'When the job completes');
|
||||
private readonly JobCompletionActionCondition_OnFailure: string = localize('jobData.whenJobFails', 'When the job fails');
|
||||
private readonly JobCompletionActionCondition_OnSuccess: string = localize('jobData.whenJobSucceeds', 'When the job succeeds');
|
||||
|
||||
// Error Messages
|
||||
private readonly CreateJobErrorMessage_NameIsEmpty = 'Job name must be provided';
|
||||
private readonly CreateJobErrorMessage_NameIsEmpty = localize('jobData.jobNameRequired', 'Job name must be provided');
|
||||
|
||||
private _ownerUri: string;
|
||||
private _jobCategories: string[];
|
||||
@@ -25,6 +29,7 @@ export class JobData implements IAgentDialogData {
|
||||
|
||||
public dialogMode: AgentDialogMode = AgentDialogMode.CREATE;
|
||||
public name: string;
|
||||
public originalName: string;
|
||||
public enabled: boolean = true;
|
||||
public description: string;
|
||||
public category: string;
|
||||
@@ -40,8 +45,21 @@ export class JobData implements IAgentDialogData {
|
||||
public jobSchedules: sqlops.AgentJobScheduleInfo[];
|
||||
public alerts: sqlops.AgentAlertInfo[];
|
||||
|
||||
constructor(ownerUri: string, private _agentService: sqlops.AgentServicesProvider = null) {
|
||||
constructor(
|
||||
ownerUri: string,
|
||||
jobInfo: sqlops.AgentJobInfo = undefined,
|
||||
private _agentService: sqlops.AgentServicesProvider = undefined) {
|
||||
|
||||
this._ownerUri = ownerUri;
|
||||
if (jobInfo) {
|
||||
this.dialogMode = AgentDialogMode.EDIT;
|
||||
this.name = jobInfo.name;
|
||||
this.originalName = jobInfo.name;
|
||||
this.owner = jobInfo.owner;
|
||||
this.category = jobInfo.category;
|
||||
this.description = jobInfo.description;
|
||||
this.enabled = jobInfo.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public get jobCategories(): string[] {
|
||||
@@ -92,7 +110,39 @@ export class JobData implements IAgentDialogData {
|
||||
}
|
||||
|
||||
public async save() {
|
||||
await this._agentService.createJob(this.ownerUri, {
|
||||
let jobInfo: sqlops.AgentJobInfo = this.toAgentJobInfo();
|
||||
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'));
|
||||
}
|
||||
}
|
||||
|
||||
public validate(): { valid: boolean, errorMessages: string[] } {
|
||||
let validationErrors: string[] = [];
|
||||
|
||||
if (!(this.name && this.name.trim())) {
|
||||
validationErrors.push(this.CreateJobErrorMessage_NameIsEmpty);
|
||||
}
|
||||
|
||||
return {
|
||||
valid: validationErrors.length === 0,
|
||||
errorMessages: validationErrors
|
||||
};
|
||||
}
|
||||
|
||||
public addJobSchedule(schedule: sqlops.AgentJobScheduleInfo) {
|
||||
let existingSchedule = this.jobSchedules.find(item => item.name === schedule.name);
|
||||
if (!existingSchedule) {
|
||||
this.jobSchedules.push(schedule);
|
||||
}
|
||||
}
|
||||
|
||||
public toAgentJobInfo(): sqlops.AgentJobInfo {
|
||||
return {
|
||||
name: this.name,
|
||||
owner: this.owner,
|
||||
description: this.description,
|
||||
@@ -122,30 +172,6 @@ export class JobData implements IAgentDialogData {
|
||||
lastRun: '',
|
||||
nextRun: '',
|
||||
jobId: ''
|
||||
}).then(result => {
|
||||
if (!result.success) {
|
||||
console.info(result.errorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public validate(): { valid: boolean, errorMessages: string[] } {
|
||||
let validationErrors: string[] = [];
|
||||
|
||||
if (!(this.name && this.name.trim())) {
|
||||
validationErrors.push(this.CreateJobErrorMessage_NameIsEmpty);
|
||||
}
|
||||
|
||||
return {
|
||||
valid: validationErrors.length === 0,
|
||||
errorMessages: validationErrors
|
||||
};
|
||||
}
|
||||
|
||||
public addJobSchedule(schedule: sqlops.AgentJobScheduleInfo) {
|
||||
let existingSchedule = this.jobSchedules.find(item => item.name === schedule.name);
|
||||
if (!existingSchedule) {
|
||||
this.jobSchedules.push(schedule);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,8 +29,14 @@ export class OperatorData implements IAgentDialogData {
|
||||
weekdayPagerStartTime: string;
|
||||
weekdayPagerEndTime: string;
|
||||
|
||||
constructor(ownerUri:string) {
|
||||
constructor(ownerUri:string, operatorInfo: sqlops.AgentOperatorInfo) {
|
||||
this.ownerUri = ownerUri;
|
||||
|
||||
if (operatorInfo) {
|
||||
this.dialogMode = AgentDialogMode.EDIT;
|
||||
this.name = operatorInfo.name;
|
||||
this.enabled = operatorInfo.enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public async initialize() {
|
||||
|
||||
@@ -19,8 +19,14 @@ export class ProxyData implements IAgentDialogData {
|
||||
credentialId: number;
|
||||
isEnabled: boolean;
|
||||
|
||||
constructor(ownerUri:string) {
|
||||
constructor(ownerUri:string, proxyInfo: sqlops.AgentProxyInfo) {
|
||||
this.ownerUri = ownerUri;
|
||||
|
||||
if (proxyInfo) {
|
||||
this.accountName = proxyInfo.accountName;
|
||||
this.credentialName = proxyInfo.credentialName;
|
||||
this.description = proxyInfo.description;
|
||||
}
|
||||
}
|
||||
|
||||
public async initialize() {
|
||||
|
||||
@@ -10,6 +10,8 @@ import * as sqlops from 'sqlops';
|
||||
import { AgentDialog } from './agentDialog';
|
||||
import { AgentUtils } from '../agentUtils';
|
||||
import { AlertData } from '../data/alertData';
|
||||
import { OperatorDialog } from './operatorDialog';
|
||||
import { JobDialog } from './jobDialog';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -21,6 +23,7 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
||||
private static readonly GeneralTabText: string = localize('alertDialog.General', 'General');
|
||||
private static readonly ResponseTabText: string = localize('alertDialog.Response', 'Response');
|
||||
private static readonly OptionsTabText: string = localize('alertDialog.Options', 'Options');
|
||||
private static readonly EventAlertText: string = localize('alertDialog.eventAlert', 'Event alert definition');
|
||||
|
||||
// General tab strings
|
||||
private static readonly NameLabel: string = localize('alertDialog.Name', 'Name');
|
||||
@@ -31,9 +34,6 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
||||
private static readonly SeverityLabel: string = localize('alertDialog.Severity', 'Severity');
|
||||
private static readonly RaiseIfMessageContainsLabel: string = localize('alertDialog.RaiseAlertContains', 'Raise alert when message contains');
|
||||
private static readonly MessageTextLabel: string = localize('alertDialog.MessageText', 'Message text');
|
||||
private static readonly AlertTypeSqlServerEventString: string = localize('alertDialog.SqlServerEventAlert', 'SQL Server event alert');
|
||||
private static readonly AlertTypePerformanceConditionString: string = localize('alertDialog.PerformanceCondition', 'SQL Server performance condition alert');
|
||||
private static readonly AlertTypeWmiEventString: string = localize('alertDialog.WmiEvent', 'WMI event alert');
|
||||
private static readonly AlertSeverity001Label: string = localize('alertDialog.Severity001', '001 - Miscellaneous System Information');
|
||||
private static readonly AlertSeverity002Label: string = localize('alertDialog.Severity002', '002 - Reserved');
|
||||
private static readonly AlertSeverity003Label: string = localize('alertDialog.Severity003', '003 - Reserved');
|
||||
@@ -59,11 +59,12 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
||||
private static readonly AlertSeverity023Label: string = localize('alertDialog.Severity023', '023 - Fatal Error: Database Integrity Suspect');
|
||||
private static readonly AlertSeverity024Label: string = localize('alertDialog.Severity024', '024 - Fatal Error: Hardware Error');
|
||||
private static readonly AlertSeverity025Label: string = localize('alertDialog.Severity025', '025 - Fatal Error');
|
||||
private static readonly AllDatabases: string = localize('alertDialog.AllDatabases', '<all databases>');
|
||||
|
||||
private static readonly AlertTypes: string[] = [
|
||||
AlertDialog.AlertTypeSqlServerEventString,
|
||||
AlertDialog.AlertTypePerformanceConditionString,
|
||||
AlertDialog.AlertTypeWmiEventString
|
||||
AlertData.AlertTypeSqlServerEventString,
|
||||
AlertData.AlertTypePerformanceConditionString,
|
||||
AlertData.AlertTypeWmiEventString
|
||||
];
|
||||
|
||||
private static readonly AlertSeverities: string[] = [
|
||||
@@ -124,6 +125,10 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
||||
private severityDropDown: sqlops.DropDownComponent;
|
||||
private databaseDropDown: sqlops.DropDownComponent;
|
||||
private enabledCheckBox: sqlops.CheckBoxComponent;
|
||||
private errorNumberRadioButton: sqlops.RadioButtonComponent;
|
||||
private severityRadioButton: sqlops.RadioButtonComponent;
|
||||
private errorNumberTextBox: sqlops.InputBoxComponent;
|
||||
|
||||
private raiseAlertMessageCheckBox: sqlops.CheckBoxComponent;
|
||||
private raiseAlertMessageTextBox: sqlops.InputBoxComponent;
|
||||
|
||||
@@ -142,58 +147,115 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
||||
private delayMinutesTextBox: sqlops.InputBoxComponent;
|
||||
private delaySecondsTextBox: sqlops.InputBoxComponent;
|
||||
|
||||
constructor(ownerUri: string, alertInfo: sqlops.AgentAlertInfo = null) {
|
||||
private jobs: string[];
|
||||
private databases: string[];
|
||||
|
||||
constructor(ownerUri: string, alertInfo: sqlops.AgentAlertInfo = undefined, jobs: string[]) {
|
||||
super(ownerUri,
|
||||
new AlertData(ownerUri, alertInfo),
|
||||
alertInfo ? AlertDialog.EditDialogTitle : AlertDialog.CreateDialogTitle);
|
||||
this.jobs = jobs;
|
||||
}
|
||||
|
||||
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
let databases = await AgentUtils.getDatabases(this.ownerUri);
|
||||
this.databases = await AgentUtils.getDatabases(this.ownerUri);
|
||||
this.databases.unshift(AlertDialog.AllDatabases);
|
||||
|
||||
this.generalTab = sqlops.window.modelviewdialog.createTab(AlertDialog.GeneralTabText);
|
||||
this.responseTab = sqlops.window.modelviewdialog.createTab(AlertDialog.ResponseTabText);
|
||||
this.optionsTab = sqlops.window.modelviewdialog.createTab(AlertDialog.OptionsTabText);
|
||||
|
||||
this.initializeGeneralTab(databases);
|
||||
this.initializeGeneralTab(this.databases, dialog);
|
||||
this.initializeResponseTab();
|
||||
this.initializeOptionsTab();
|
||||
|
||||
dialog.content = [this.generalTab, this.responseTab, this.optionsTab];
|
||||
}
|
||||
|
||||
private initializeGeneralTab(databases: string[]) {
|
||||
private initializeGeneralTab(databases: string[], dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
this.generalTab.registerContent(async view => {
|
||||
// create controls
|
||||
this.nameTextBox = view.modelBuilder.inputBox().component();
|
||||
|
||||
this.nameTextBox.required = true;
|
||||
this.nameTextBox.onTextChanged(() => {
|
||||
if (this.nameTextBox.value.length > 0) {
|
||||
dialog.okButton.enabled = true;
|
||||
} else {
|
||||
dialog.okButton.enabled = false;
|
||||
}
|
||||
});
|
||||
this.enabledCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: AlertDialog.EnabledCheckboxLabel
|
||||
}).component();
|
||||
|
||||
this.enabledCheckBox.checked = true;
|
||||
|
||||
this.databaseDropDown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: databases[0],
|
||||
values: databases
|
||||
values: databases,
|
||||
width: '100%'
|
||||
}).component();
|
||||
|
||||
this.typeDropDown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: AlertDialog.AlertTypes[0],
|
||||
values: AlertDialog.AlertTypes
|
||||
value: '',
|
||||
values: AlertDialog.AlertTypes,
|
||||
width: '100%'
|
||||
}).component();
|
||||
|
||||
this.severityRadioButton = view.modelBuilder.radioButton()
|
||||
.withProperties({
|
||||
value: 'serverity',
|
||||
name: 'alertTypeOptions',
|
||||
label: AlertDialog.SeverityLabel,
|
||||
checked: true
|
||||
}).component();
|
||||
this.severityRadioButton.checked = true;
|
||||
|
||||
this.severityDropDown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: AlertDialog.AlertSeverities[0],
|
||||
values: AlertDialog.AlertSeverities
|
||||
values: AlertDialog.AlertSeverities,
|
||||
width: '100%'
|
||||
}).component();
|
||||
|
||||
this.errorNumberRadioButton = view.modelBuilder.radioButton()
|
||||
.withProperties({
|
||||
value: 'errorNumber',
|
||||
name: 'alertTypeOptions',
|
||||
label: AlertDialog.ErrorNumberLabel
|
||||
}).component();
|
||||
|
||||
this.errorNumberTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
width: '100%'
|
||||
})
|
||||
.component();
|
||||
this.errorNumberTextBox.enabled = false;
|
||||
|
||||
this.errorNumberRadioButton.onDidClick(() => {
|
||||
this.errorNumberTextBox.enabled = true;
|
||||
this.severityDropDown.enabled = false;
|
||||
});
|
||||
|
||||
this.severityRadioButton.onDidClick(() => {
|
||||
this.errorNumberTextBox.enabled = false;
|
||||
this.severityDropDown.enabled = true;
|
||||
});
|
||||
|
||||
this.raiseAlertMessageCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: AlertDialog.RaiseIfMessageContainsLabel
|
||||
}).component();
|
||||
|
||||
this.raiseAlertMessageTextBox = view.modelBuilder.inputBox().component();
|
||||
this.raiseAlertMessageTextBox.enabled = false;
|
||||
|
||||
this.raiseAlertMessageCheckBox.onChanged(() => {
|
||||
this.raiseAlertMessageTextBox.enabled = this.raiseAlertMessageCheckBox.checked;
|
||||
});
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
@@ -206,24 +268,61 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
||||
component: this.typeDropDown,
|
||||
title: AlertDialog.TypeLabel
|
||||
}, {
|
||||
component: this.databaseDropDown,
|
||||
title: AlertDialog.DatabaseLabel
|
||||
}, {
|
||||
component: this.severityDropDown,
|
||||
title: AlertDialog.SeverityLabel
|
||||
}, {
|
||||
component: this.raiseAlertMessageCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.raiseAlertMessageTextBox,
|
||||
title: AlertDialog.MessageTextLabel
|
||||
components: [{
|
||||
component: this.databaseDropDown,
|
||||
title: AlertDialog.DatabaseLabel
|
||||
},
|
||||
{
|
||||
component: this.severityRadioButton,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: this.severityDropDown,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: this.errorNumberRadioButton,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: this.errorNumberTextBox,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: this.raiseAlertMessageCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.raiseAlertMessageTextBox,
|
||||
title: AlertDialog.MessageTextLabel
|
||||
}],
|
||||
title: AlertDialog.EventAlertText
|
||||
}
|
||||
]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
// initialize control values
|
||||
this.nameTextBox.value = this.model.name;
|
||||
this.raiseAlertMessageTextBox.value = this.model.eventDescriptionKeyword;
|
||||
this.typeDropDown.value = this.model.alertType;
|
||||
this.enabledCheckBox.checked = this.model.isEnabled;
|
||||
|
||||
if (this.model.messageId > 0) {
|
||||
this.errorNumberRadioButton.checked = true;
|
||||
this.errorNumberTextBox.value = this.model.messageId.toString();
|
||||
}
|
||||
|
||||
if (this.model.severity > 0) {
|
||||
this.severityRadioButton.checked = true;
|
||||
this.severityDropDown.value = this.severityDropDown.values[this.model.severity-1];
|
||||
}
|
||||
|
||||
if (this.model.databaseName) {
|
||||
let idx = this.databases.indexOf(this.model.databaseName);
|
||||
if (idx >= 0) {
|
||||
this.databaseDropDown.value = this.databases[idx];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -234,12 +333,38 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
||||
label: AlertDialog.ExecuteJobCheckBoxLabel
|
||||
}).component();
|
||||
|
||||
this.executeJobTextBox = view.modelBuilder.inputBox().component();
|
||||
|
||||
this.executeJobTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({ width: 375 })
|
||||
.component();
|
||||
this.executeJobTextBox.enabled = false;
|
||||
this.newJobButton = view.modelBuilder.button().withProperties({
|
||||
label: AlertDialog.NewJobButtonLabel,
|
||||
width: 80
|
||||
}).component();
|
||||
this.newJobButton.enabled = false;
|
||||
this.newJobButton.onDidClick(() => {
|
||||
let jobDialog = new JobDialog(this.ownerUri);
|
||||
jobDialog.openDialog();
|
||||
});
|
||||
|
||||
this.executeJobCheckBox.onChanged(() => {
|
||||
if (this.executeJobCheckBox.checked) {
|
||||
this.executeJobTextBox.enabled = true;
|
||||
this.newJobButton.enabled = true;
|
||||
} else {
|
||||
this.executeJobTextBox.enabled = false;
|
||||
this.newJobButton.enabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
let executeJobContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.executeJobTextBox,
|
||||
title: AlertDialog.ExecuteJobTextBoxLabel
|
||||
}, {
|
||||
component: this.newJobButton,
|
||||
title: AlertDialog.NewJobButtonLabel
|
||||
}], { componentWidth: '100%'}).component();
|
||||
|
||||
this.notifyOperatorsCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
@@ -254,32 +379,57 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
||||
AlertDialog.OperatorPagerColumnLabel
|
||||
],
|
||||
data: [],
|
||||
height: 500
|
||||
height: 500,
|
||||
width: 375
|
||||
}).component();
|
||||
|
||||
this.newOperatorButton = view.modelBuilder.button().withProperties({
|
||||
label: this.newOperatorButton,
|
||||
label: AlertDialog.NewOperatorButtonLabel,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.operatorsTable.enabled = false;
|
||||
this.newOperatorButton.enabled = false;
|
||||
|
||||
this.newOperatorButton.onDidClick(() => {
|
||||
let operatorDialog = new OperatorDialog(this.ownerUri);
|
||||
operatorDialog.openDialog();
|
||||
});
|
||||
|
||||
this.notifyOperatorsCheckBox.onChanged(() => {
|
||||
if (this.notifyOperatorsCheckBox.checked) {
|
||||
this.operatorsTable.enabled = true;
|
||||
this.newOperatorButton.enabled = true;
|
||||
} else {
|
||||
this.operatorsTable.enabled = false;
|
||||
this.newOperatorButton.enabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
let notifyOperatorContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.operatorsTable,
|
||||
title: AlertDialog.OperatorListLabel
|
||||
}, {
|
||||
component: this.newOperatorButton,
|
||||
title: ''
|
||||
}], { componentWidth: '100%'}).component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.executeJobCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.executeJobTextBox,
|
||||
title: AlertDialog.ExecuteJobTextBoxLabel
|
||||
}, {
|
||||
component: this.newJobButton,
|
||||
title: AlertDialog.NewJobButtonLabel
|
||||
component: executeJobContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.notifyOperatorsCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.operatorsTable,
|
||||
title: AlertDialog.OperatorListLabel,
|
||||
actions: [this.newOperatorButton]
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
component: notifyOperatorContainer,
|
||||
title: ''
|
||||
}])
|
||||
.withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
});
|
||||
@@ -300,9 +450,19 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
||||
|
||||
this.additionalMessageTextBox = view.modelBuilder.inputBox().component();
|
||||
|
||||
this.delayMinutesTextBox = view.modelBuilder.inputBox().component();
|
||||
this.delayMinutesTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
inputType: 'number',
|
||||
placeHolder: 0
|
||||
})
|
||||
.component();
|
||||
|
||||
this.delaySecondsTextBox = view.modelBuilder.inputBox().component();
|
||||
this.delaySecondsTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
inputType: 'number',
|
||||
placeHolder: 0
|
||||
})
|
||||
.component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
@@ -343,13 +503,25 @@ export class AlertDialog extends AgentDialog<AlertData> {
|
||||
this.model.isEnabled = this.enabledCheckBox.checked;
|
||||
|
||||
this.model.alertType = this.getDropdownValue(this.typeDropDown);
|
||||
this.model.databaseName = this.getDropdownValue(this.databaseDropDown);
|
||||
this.model.severity = this.getSeverityNumber();
|
||||
this.model.messageId = undefined;
|
||||
let databaseName = this.getDropdownValue(this.databaseDropDown);
|
||||
this.model.databaseName = (databaseName !== AlertDialog.AllDatabases) ? databaseName : undefined;
|
||||
|
||||
let raiseIfError = this.raiseAlertMessageCheckBox.checked;
|
||||
if (raiseIfError) {
|
||||
let messageText = this.raiseAlertMessageTextBox.value;
|
||||
if (this.severityRadioButton.checked) {
|
||||
this.model.severity = this.getSeverityNumber();
|
||||
this.model.messageId = 0;
|
||||
} else {
|
||||
this.model.severity = 0;
|
||||
this.model.messageId = +this.errorNumberTextBox.value;
|
||||
}
|
||||
|
||||
if (this.raiseAlertMessageCheckBox.checked) {
|
||||
this.model.eventDescriptionKeyword = this.raiseAlertMessageTextBox.value;
|
||||
} else {
|
||||
this.model.eventDescriptionKeyword = '';
|
||||
}
|
||||
let minutes = this.delayMinutesTextBox.value ? +this.delayMinutesTextBox.value : 0;
|
||||
let seconds = this.delaySecondsTextBox.value ? +this.delaySecondsTextBox : 0;
|
||||
this.model.delayBetweenResponses = minutes + seconds;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import { JobData } from '../data/jobData';
|
||||
import { JobStepDialog } from './jobStepDialog';
|
||||
@@ -10,50 +11,57 @@ import { PickScheduleDialog } from './pickScheduleDialog';
|
||||
import { AlertDialog } from './alertDialog';
|
||||
import { AgentDialog } from './agentDialog';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class JobDialog extends AgentDialog<JobData> {
|
||||
|
||||
// TODO: localize
|
||||
// Top level
|
||||
private static readonly DialogTitle: string = 'New Job';
|
||||
private readonly GeneralTabText: string = 'General';
|
||||
private readonly StepsTabText: string = 'Steps';
|
||||
private readonly SchedulesTabText: string = 'Schedules';
|
||||
private readonly AlertsTabText: string = 'Alerts';
|
||||
private readonly NotificationsTabText: string = 'Notifications';
|
||||
private static readonly CreateDialogTitle: string = localize('jobDialog.newJob', 'New Job');
|
||||
private static readonly EditDialogTitle: string = localize('jobDialog.editJob', 'Edit Job');
|
||||
private readonly GeneralTabText: string = localize('jobDialog.general', 'General');
|
||||
private readonly StepsTabText: string = localize('jobDialog.steps', 'Steps');
|
||||
private readonly SchedulesTabText: string = localize('jobDialog.schedules', 'Schedules');
|
||||
private readonly AlertsTabText: string = localize('jobDialog.alerts', 'Alerts');
|
||||
private readonly NotificationsTabText: string = localize('jobDialog.notifications', 'Notifications');
|
||||
private readonly BlankJobNameErrorText: string = localize('jobDialog.blankJobNameError', 'The name of the job cannot be blank.');
|
||||
|
||||
// General tab strings
|
||||
private readonly NameTextBoxLabel: string = 'Name';
|
||||
private readonly OwnerTextBoxLabel: string = 'Owner';
|
||||
private readonly CategoryDropdownLabel: string = 'Category';
|
||||
private readonly DescriptionTextBoxLabel: string = 'Description';
|
||||
private readonly EnabledCheckboxLabel: string = 'Enabled';
|
||||
private readonly NameTextBoxLabel: string = localize('jobDialog.name', 'Name');
|
||||
private readonly OwnerTextBoxLabel: string = localize('jobDialog.owner', 'Owner');
|
||||
private readonly CategoryDropdownLabel: string = localize('jobDialog.category', 'Category');
|
||||
private readonly DescriptionTextBoxLabel: string = localize('jobDialog.description', 'Description');
|
||||
private readonly EnabledCheckboxLabel: string = localize('jobDialog.enabled', 'Enabled');
|
||||
|
||||
// Steps tab strings
|
||||
private readonly JobStepsTopLabelString: string = 'Job step list';
|
||||
private readonly StepsTable_StepColumnString: string = 'Step';
|
||||
private readonly StepsTable_NameColumnString: string = 'Name';
|
||||
private readonly StepsTable_TypeColumnString: string = 'Type';
|
||||
private readonly StepsTable_SuccessColumnString: string = 'On Success';
|
||||
private readonly StepsTable_FailureColumnString: string = 'On Failure';
|
||||
private readonly NewStepButtonString: string = 'New...';
|
||||
private readonly InsertStepButtonString: string = 'Insert...';
|
||||
private readonly EditStepButtonString: string = 'Edit';
|
||||
private readonly DeleteStepButtonString: string = 'Delete';
|
||||
private readonly JobStepsTopLabelString: string = localize('jobDialog.jobStepList', 'Job step list');
|
||||
private readonly StepsTable_StepColumnString: string = localize('jobDialog.step', 'Step');
|
||||
private readonly StepsTable_NameColumnString: string = localize('jobDialog.name', 'Name');
|
||||
private readonly StepsTable_TypeColumnString: string = localize('jobDialog.type', 'Type');
|
||||
private readonly StepsTable_SuccessColumnString: string = localize('jobDialog.onSuccess', 'On Success');
|
||||
private readonly StepsTable_FailureColumnString: string = localize('jobDialog.onFailure', 'On Failure');
|
||||
private readonly NewStepButtonString: string = localize('jobDialog.new', 'New...');
|
||||
private readonly EditStepButtonString: string = localize('jobDialog.edit', 'Edit');
|
||||
private readonly DeleteStepButtonString: string = localize('jobDialog.delete', 'Delete');
|
||||
private readonly MoveStepUpButtonString: string = localize('jobDialog.moveUp', 'Move Step Up');
|
||||
private readonly MoveStepDownButtonString: string = localize('jobDialog.moveDown', 'Move Step Up');
|
||||
|
||||
// Notifications tab strings
|
||||
private readonly NotificationsTabTopLabelString: string = 'Actions to perform when the job completes';
|
||||
private readonly EmailCheckBoxString: string = 'Email';
|
||||
private readonly PagerCheckBoxString: string = 'Page';
|
||||
private readonly EventLogCheckBoxString: string = 'Write to the Windows Application event log';
|
||||
private readonly DeleteJobCheckBoxString: string = 'Automatically delete job';
|
||||
private readonly NotificationsTabTopLabelString: string = localize('jobDialog.notificationsTabTop', 'Actions to perform when the job completes');
|
||||
private readonly EmailCheckBoxString: string = localize('jobDialog.email', 'Email');
|
||||
private readonly PagerCheckBoxString: string = localize('jobDialog.page', 'Page');
|
||||
private readonly EventLogCheckBoxString: string = localize('jobDialog.eventLogCheckBoxLabel', 'Write to the Windows Application event log');
|
||||
private readonly DeleteJobCheckBoxString: string = localize('jobDialog.deleteJobLabel', 'Automatically delete job');
|
||||
|
||||
// Schedules tab strings
|
||||
private readonly SchedulesTopLabelString: string = 'Schedules list';
|
||||
private readonly PickScheduleButtonString: string = 'Pick Schedule';
|
||||
private readonly SchedulesTopLabelString: string = localize('jobDialog.schedulesaLabel', 'Schedules list');
|
||||
private readonly PickScheduleButtonString: string = localize('jobDialog.pickSchedule', 'Pick Schedule');
|
||||
private readonly ScheduleNameLabelString: string = localize('jobDialog.scheduleNameLabel', 'Schedule Name');
|
||||
|
||||
// Alerts tab strings
|
||||
private readonly AlertsTopLabelString: string = 'Alerts list';
|
||||
private readonly NewAlertButtonString: string = 'New Alert';
|
||||
private readonly AlertsTopLabelString: string = localize('jobDialog.alertsList', 'Alerts list');
|
||||
private readonly NewAlertButtonString: string = localize('jobDialog.newAlert', 'New Alert');
|
||||
private readonly AlertNameLabelString: string = localize('jobDialog.alertNameLabel', 'Alert Name');
|
||||
|
||||
// UI Components
|
||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
@@ -72,7 +80,8 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
// Steps tab controls
|
||||
private stepsTable: sqlops.TableComponent;
|
||||
private newStepButton: sqlops.ButtonComponent;
|
||||
private insertStepButton: sqlops.ButtonComponent;
|
||||
private moveStepUpButton: sqlops.ButtonComponent;
|
||||
private moveStepDownButton: sqlops.ButtonComponent;
|
||||
private editStepButton: sqlops.ButtonComponent;
|
||||
private deleteStepButton: sqlops.ButtonComponent;
|
||||
|
||||
@@ -97,8 +106,11 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
private alertsTable: sqlops.TableComponent;
|
||||
private newAlertButton: sqlops.ButtonComponent;
|
||||
|
||||
constructor(ownerUri: string) {
|
||||
super(ownerUri, new JobData(ownerUri), JobDialog.DialogTitle);
|
||||
constructor(ownerUri: string, jobInfo: sqlops.AgentJobInfo = undefined) {
|
||||
super(
|
||||
ownerUri,
|
||||
new JobData(ownerUri, jobInfo),
|
||||
jobInfo ? JobDialog.EditDialogTitle : JobDialog.CreateDialogTitle);
|
||||
}
|
||||
|
||||
protected async initializeDialog() {
|
||||
@@ -129,6 +141,12 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
private initializeGeneralTab() {
|
||||
this.generalTab.registerContent(async view => {
|
||||
this.nameTextBox = view.modelBuilder.inputBox().component();
|
||||
this.nameTextBox.required = true;
|
||||
this.nameTextBox.onTextChanged(() => {
|
||||
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
|
||||
this.dialog.message = null;
|
||||
}
|
||||
});
|
||||
this.ownerTextBox = view.modelBuilder.inputBox().component();
|
||||
this.categoryDropdown = view.modelBuilder.dropDown().component();
|
||||
this.descriptionTextBox = view.modelBuilder.inputBox().withProperties({
|
||||
@@ -159,11 +177,18 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
this.nameTextBox.value = this.model.name;
|
||||
this.ownerTextBox.value = this.model.defaultOwner;
|
||||
this.categoryDropdown.values = this.model.jobCategories;
|
||||
this.categoryDropdown.value = this.model.jobCategories[0];
|
||||
|
||||
let idx: number = undefined;
|
||||
if (this.model.category && this.model.category !== '') {
|
||||
idx = this.model.jobCategories.indexOf(this.model.category);
|
||||
}
|
||||
this.categoryDropdown.value = this.model.jobCategories[idx > 0 ? idx : 0];
|
||||
|
||||
this.enabledCheckBox.checked = this.model.enabled;
|
||||
this.descriptionTextBox.value = '';
|
||||
this.descriptionTextBox.value = this.model.description;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -179,7 +204,19 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
this.StepsTable_FailureColumnString
|
||||
],
|
||||
data: [],
|
||||
height: 800
|
||||
height: 430
|
||||
}).component();
|
||||
|
||||
this.moveStepUpButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: this.MoveStepUpButtonString,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.moveStepDownButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: this.MoveStepDownButtonString,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.newStepButton = view.modelBuilder.button().withProperties({
|
||||
@@ -188,15 +225,14 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
}).component();
|
||||
|
||||
this.newStepButton.onDidClick((e)=>{
|
||||
let stepDialog = new JobStepDialog(this.model.ownerUri, '', '', 1, this.model);
|
||||
stepDialog.openNewStepDialog();
|
||||
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
|
||||
let stepDialog = new JobStepDialog(this.model.ownerUri, this.nameTextBox.value, '' , 1, this.model);
|
||||
stepDialog.openNewStepDialog();
|
||||
} else {
|
||||
this.dialog.message = { text: this.BlankJobNameErrorText };
|
||||
}
|
||||
});
|
||||
|
||||
this.insertStepButton = view.modelBuilder.button().withProperties({
|
||||
label: this.InsertStepButtonString,
|
||||
width: 80
|
||||
}).component();
|
||||
|
||||
this.editStepButton = view.modelBuilder.button().withProperties({
|
||||
label: this.EditStepButtonString,
|
||||
width: 80
|
||||
@@ -211,7 +247,7 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
.withFormItems([{
|
||||
component: this.stepsTable,
|
||||
title: this.JobStepsTopLabelString,
|
||||
actions: [this.newStepButton, this.insertStepButton, this.editStepButton, this.deleteStepButton]
|
||||
actions: [this.moveStepUpButton, this.moveStepDownButton, this.newStepButton, this.editStepButton, this.deleteStepButton]
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
await view.initializeModel(formModel);
|
||||
});
|
||||
@@ -222,10 +258,10 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
this.alertsTable = view.modelBuilder.table()
|
||||
.withProperties({
|
||||
columns: [
|
||||
'Alert Name'
|
||||
this.AlertNameLabelString
|
||||
],
|
||||
data: [],
|
||||
height: 600,
|
||||
height: 430,
|
||||
width: 400
|
||||
}).component();
|
||||
|
||||
@@ -235,7 +271,7 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
}).component();
|
||||
|
||||
this.newAlertButton.onDidClick((e)=>{
|
||||
let alertDialog = new AlertDialog(this.model.ownerUri);
|
||||
let alertDialog = new AlertDialog(this.model.ownerUri, null, []);
|
||||
alertDialog.onSuccess((dialogModel) => {
|
||||
});
|
||||
alertDialog.openDialog();
|
||||
@@ -257,11 +293,11 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
this.schedulesTable = view.modelBuilder.table()
|
||||
.withProperties({
|
||||
columns: [
|
||||
'Schedule Name'
|
||||
this.ScheduleNameLabelString
|
||||
],
|
||||
data: [],
|
||||
height: 600,
|
||||
width: 400
|
||||
height: 430,
|
||||
width: 420
|
||||
}).component();
|
||||
|
||||
this.pickScheduleButton = view.modelBuilder.button().withProperties({
|
||||
@@ -361,21 +397,23 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
|
||||
let formModel = view.modelBuilder.formContainer().withFormItems([
|
||||
{
|
||||
component: this.notificationsTabTopLabel,
|
||||
title: ''
|
||||
}, {
|
||||
component: emailContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: pagerContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: eventLogContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: deleteJobContainer,
|
||||
title: ''
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
components:
|
||||
[{
|
||||
component: emailContainer,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: pagerContainer,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: eventLogContainer,
|
||||
title: ''
|
||||
},
|
||||
{
|
||||
component: deleteJobContainer,
|
||||
title: ''
|
||||
}], title: this.NotificationsTabTopLabelString}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
this.emailConditionDropdown.values = this.model.JobCompletionActionConditions;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { JobStepData } from '../data/jobStepData';
|
||||
@@ -10,31 +11,57 @@ import { AgentUtils } from '../agentUtils';
|
||||
import { JobData } from '../data/jobData';
|
||||
const path = require('path');
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class JobStepDialog {
|
||||
|
||||
// TODO: localize
|
||||
// Top level
|
||||
//
|
||||
private static readonly DialogTitle: string = 'New Job Step';
|
||||
private static readonly FileBrowserDialogTitle: string = 'Locate Database Files - ';
|
||||
private static readonly OkButtonText: string = 'OK';
|
||||
private static readonly CancelButtonText: string = 'Cancel';
|
||||
private static readonly GeneralTabText: string = 'General';
|
||||
private static readonly AdvancedTabText: string = 'Advanced';
|
||||
private static readonly OpenCommandText: string = 'Open...';
|
||||
private static readonly ParseCommandText: string = 'Parse';
|
||||
private static readonly NextButtonText: string = 'Next';
|
||||
private static readonly PreviousButtonText: string = 'Previous';
|
||||
private static readonly SuccessAction: string = 'On success action';
|
||||
private static readonly FailureAction: string = 'On failure action';
|
||||
private readonly DialogTitle: string = localize('jobStepDialog.newJobStep', 'New Job Step');
|
||||
private readonly FileBrowserDialogTitle: string = localize('jobStepDialog.fileBrowserTitle', 'Locate Database Files - ');
|
||||
private readonly OkButtonText: string = localize('jobStepDialog.ok', 'OK');
|
||||
private readonly CancelButtonText: string = localize('jobStepDialog.cancel', 'Cancel');
|
||||
private readonly GeneralTabText: string = localize('jobStepDialog.general', 'General');
|
||||
private readonly AdvancedTabText: string = localize('jobStepDialog.advanced', 'Advanced');
|
||||
private readonly OpenCommandText: string = localize('jobStepDialog.open', 'Open...');
|
||||
private readonly ParseCommandText: string = localize('jobStepDialog.parse','Parse');
|
||||
private readonly NextButtonText: string = localize('jobStepDialog.next', 'Next');
|
||||
private readonly PreviousButtonText: string = localize('jobStepDialog.previous','Previous');
|
||||
private readonly SuccessfulParseText: string = localize('jobStepDialog.successParse', 'The command was successfully parsed.');
|
||||
private readonly FailureParseText: string = localize('jobStepDialog.failParse', 'The command failed.');
|
||||
|
||||
// General Control Titles
|
||||
private readonly StepNameLabelString: string = localize('jobStepDialog.stepNameLabel', 'Step Name');
|
||||
private readonly TypeLabelString: string = localize('jobStepDialog.typeLabel', 'Type');
|
||||
private readonly RunAsLabelString: string = localize('jobStepDialog.runAsLabel', 'Run as');
|
||||
private readonly DatabaseLabelString: string = localize('jobStepDialog.databaseLabel', 'Database');
|
||||
private readonly CommandLabelString: string = localize('jobStepDialog.commandLabel', 'Command');
|
||||
|
||||
// Advanced Control Titles
|
||||
private readonly SuccessActionLabel: string = localize('jobStepDialog.successAction', 'On success action');
|
||||
private readonly FailureActionLabel: string = localize('jobStepDialog.failureAction', 'On failure action');
|
||||
private readonly RunAsUserLabel: string = localize('jobStepDialog.runAsUser', 'Run as user');
|
||||
private readonly RetryAttemptsLabel: string = localize('jobStepDialog.retryAttempts', 'Retry Attempts');
|
||||
private readonly RetryIntervalLabel: string = localize('jobStepDialog.retryInterval', 'Retry Interval (minutes)');
|
||||
private readonly LogToTableLabel: string = localize('jobStepDialog.logToTable', 'Log to table');
|
||||
private readonly AppendExistingTableEntryLabel: string = localize('jobStepDialog.appendExistingTableEntry', 'Append output to exisiting entry in table');
|
||||
private readonly IncludeStepOutputHistoryLabel: string = localize('jobStepDialog.includeStepOutputHistory', 'Include step output in history');
|
||||
private readonly OutputFileNameLabel: string = localize('jobStepDialog.outputFile', 'Output File');
|
||||
private readonly AppendOutputToFileLabel: string = localize('jobStepDialog.appendOutputToFile', 'Append output to existing file');
|
||||
|
||||
// File Browser Control Titles
|
||||
private readonly SelectedPathLabelString: string = localize('jobStepDialog.selectedPath', 'Selected path');
|
||||
private readonly FilesOfTypeLabelString: string = localize('jobStepDialog.filesOfType', 'Files of type');
|
||||
private readonly FileNameLabelString: string = localize('jobStepDialog.fileName', 'File name');
|
||||
private readonly AllFilesLabelString: string = localize('jobStepDialog.allFiles', 'All Files (*)');
|
||||
|
||||
// Dropdown options
|
||||
private static readonly TSQLScript: string = 'Transact-SQL script (T-SQL)';
|
||||
private static readonly AgentServiceAccount: string = 'SQL Server Agent Service Account';
|
||||
private static readonly NextStep: string = 'Go to the next step';
|
||||
private static readonly QuitJobReportingSuccess: string = 'Quit the job reporting success';
|
||||
private static readonly QuitJobReportingFailure: string = 'Quit the job reporting failure';
|
||||
private readonly TSQLScript: string = localize('jobStepDialog.TSQL', 'Transact-SQL script (T-SQL)');
|
||||
private readonly AgentServiceAccount: string = localize('jobStepDialog.agentServiceAccount', 'SQL Server Agent Service Account');
|
||||
private readonly NextStep: string = localize('jobStepDialog.nextStep', 'Go to the next step');
|
||||
private readonly QuitJobReportingSuccess: string = localize('jobStepDialog.quitJobSuccess', 'Quit the job reporting success');
|
||||
private readonly QuitJobReportingFailure: string = localize('jobStepDialog.quitJobFailure', 'Quit the job reporting failure');
|
||||
|
||||
// UI Components
|
||||
|
||||
@@ -54,6 +81,7 @@ export class JobStepDialog {
|
||||
private retryIntervalBox: sqlops.InputBoxComponent;
|
||||
private outputFileNameBox: sqlops.InputBoxComponent;
|
||||
private fileBrowserNameBox: sqlops.InputBoxComponent;
|
||||
private userInputBox: sqlops.InputBoxComponent;
|
||||
|
||||
// Dropdowns
|
||||
private typeDropdown: sqlops.DropDownComponent;
|
||||
@@ -98,33 +126,33 @@ export class JobStepDialog {
|
||||
}
|
||||
|
||||
private initializeUIComponents() {
|
||||
this.dialog = sqlops.window.modelviewdialog.createDialog(JobStepDialog.DialogTitle);
|
||||
this.generalTab = sqlops.window.modelviewdialog.createTab(JobStepDialog.GeneralTabText);
|
||||
this.advancedTab = sqlops.window.modelviewdialog.createTab(JobStepDialog.AdvancedTabText);
|
||||
this.dialog = sqlops.window.modelviewdialog.createDialog(this.DialogTitle);
|
||||
this.generalTab = sqlops.window.modelviewdialog.createTab(this.GeneralTabText);
|
||||
this.advancedTab = sqlops.window.modelviewdialog.createTab(this.AdvancedTabText);
|
||||
this.dialog.content = [this.generalTab, this.advancedTab];
|
||||
this.dialog.okButton.onClick(async () => await this.execute());
|
||||
this.dialog.okButton.label = JobStepDialog.OkButtonText;
|
||||
this.dialog.cancelButton.label = JobStepDialog.CancelButtonText;
|
||||
this.dialog.okButton.label = this.OkButtonText;
|
||||
this.dialog.cancelButton.label = this.CancelButtonText;
|
||||
}
|
||||
|
||||
private createCommands(view, queryProvider: sqlops.QueryProvider) {
|
||||
this.openButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: JobStepDialog.OpenCommandText,
|
||||
label: this.OpenCommandText,
|
||||
width: '80px'
|
||||
}).component();
|
||||
this.parseButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: JobStepDialog.ParseCommandText,
|
||||
label: this.ParseCommandText,
|
||||
width: '80px'
|
||||
}).component();
|
||||
this.parseButton.onDidClick(e => {
|
||||
if (this.commandTextBox.value) {
|
||||
queryProvider.parseSyntax(this.ownerUri, this.commandTextBox.value).then(result => {
|
||||
if (result && result.parseable) {
|
||||
this.dialog.message = { text: 'The command was successfully parsed.', level: 2};
|
||||
this.dialog.message = { text: this.SuccessfulParseText, level: 2};
|
||||
} else if (result && !result.parseable) {
|
||||
this.dialog.message = { text: 'The command failed' };
|
||||
this.dialog.message = { text: this.FailureParseText };
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -139,13 +167,13 @@ export class JobStepDialog {
|
||||
.component();
|
||||
this.nextButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: JobStepDialog.NextButtonText,
|
||||
label: this.NextButtonText,
|
||||
enabled: false,
|
||||
width: '80px'
|
||||
}).component();
|
||||
this.previousButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: JobStepDialog.PreviousButtonText,
|
||||
label: this.PreviousButtonText,
|
||||
enabled: false,
|
||||
width: '80px'
|
||||
}).component();
|
||||
@@ -159,8 +187,8 @@ export class JobStepDialog {
|
||||
this.nameTextBox.required = true;
|
||||
this.typeDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: JobStepDialog.TSQLScript,
|
||||
values: [JobStepDialog.TSQLScript]
|
||||
value: this.TSQLScript,
|
||||
values: [this.TSQLScript]
|
||||
})
|
||||
.component();
|
||||
this.runAsDropdown = view.modelBuilder.dropDown()
|
||||
@@ -171,8 +199,8 @@ export class JobStepDialog {
|
||||
.component();
|
||||
this.runAsDropdown.enabled = false;
|
||||
this.typeDropdown.onValueChanged((type) => {
|
||||
if (type.selected !== JobStepDialog.TSQLScript) {
|
||||
this.runAsDropdown.value = JobStepDialog.AgentServiceAccount;
|
||||
if (type.selected !== this.TSQLScript) {
|
||||
this.runAsDropdown.value = this.AgentServiceAccount;
|
||||
this.runAsDropdown.values = [this.runAsDropdown.value];
|
||||
} else {
|
||||
this.runAsDropdown.value = '';
|
||||
@@ -200,19 +228,19 @@ export class JobStepDialog {
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.nameTextBox,
|
||||
title: 'Step name'
|
||||
title: this.StepNameLabelString
|
||||
}, {
|
||||
component: this.typeDropdown,
|
||||
title: 'Type'
|
||||
title: this.TypeLabelString
|
||||
}, {
|
||||
component: this.runAsDropdown,
|
||||
title: 'Run as'
|
||||
title: this.RunAsLabelString
|
||||
}, {
|
||||
component: this.databaseDropdown,
|
||||
title: 'Database'
|
||||
title: this.DatabaseLabelString
|
||||
}, {
|
||||
component: this.commandTextBox,
|
||||
title: 'Command',
|
||||
title: this.CommandLabelString,
|
||||
actions: [buttonContainer]
|
||||
}], {
|
||||
horizontal: false,
|
||||
@@ -224,81 +252,57 @@ export class JobStepDialog {
|
||||
});
|
||||
}
|
||||
|
||||
private createRunAsUserOptions(view) {
|
||||
let userInputBox = view.modelBuilder.inputBox()
|
||||
.withProperties({ inputType: 'text', width: '100px' }).component();
|
||||
let viewButton = view.modelBuilder.button()
|
||||
.withProperties({ label: '...', width: '20px' }).component();
|
||||
let viewButtonContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({ width: 100, textAlign: 'right' })
|
||||
.withItems([viewButton], { flex: '1 1 50%' }).component();
|
||||
let userInputBoxContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({ width: 200, textAlign: 'left' })
|
||||
.withItems([userInputBox], { flex: '1 1 50%' }).component();
|
||||
let runAsUserContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({ width: 200 })
|
||||
.withItems([userInputBoxContainer, viewButtonContainer], { flex: '1 1 50%' })
|
||||
.component();
|
||||
let runAsUserForm = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: runAsUserContainer,
|
||||
title: 'Run as user'
|
||||
}], { horizontal: true, componentWidth: 200 }).component();
|
||||
return runAsUserForm;
|
||||
}
|
||||
|
||||
private createAdvancedTab() {
|
||||
this.advancedTab.registerContent(async (view) => {
|
||||
this.successActionDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: JobStepDialog.NextStep,
|
||||
values: [JobStepDialog.NextStep, JobStepDialog.QuitJobReportingSuccess, JobStepDialog.QuitJobReportingFailure]
|
||||
width: '100%',
|
||||
value: this.NextStep,
|
||||
values: [this.NextStep, this.QuitJobReportingSuccess, this.QuitJobReportingFailure]
|
||||
})
|
||||
.component();
|
||||
let retryFlexContainer = this.createRetryCounters(view);
|
||||
|
||||
this.failureActionDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: JobStepDialog.QuitJobReportingFailure,
|
||||
values: [JobStepDialog.QuitJobReportingFailure, JobStepDialog.NextStep, JobStepDialog.QuitJobReportingSuccess]
|
||||
value: this.QuitJobReportingFailure,
|
||||
values: [this.QuitJobReportingFailure, this.NextStep, this.QuitJobReportingSuccess]
|
||||
})
|
||||
.component();
|
||||
let optionsGroup = this.createTSQLOptions(view);
|
||||
let viewButton = view.modelBuilder.button()
|
||||
.withProperties({ label: 'View', width: '50px' }).component();
|
||||
viewButton.enabled = false;
|
||||
this.logToTableCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: 'Log to table'
|
||||
label: this.LogToTableLabel
|
||||
}).component();
|
||||
let appendToExistingEntryInTableCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({ label: 'Append output to existing entry in table' }).component();
|
||||
.withProperties({ label: this.AppendExistingTableEntryLabel }).component();
|
||||
appendToExistingEntryInTableCheckbox.enabled = false;
|
||||
this.logToTableCheckbox.onChanged(e => {
|
||||
viewButton.enabled = e;
|
||||
appendToExistingEntryInTableCheckbox.enabled = e;
|
||||
});
|
||||
let appendCheckboxContainer = view.modelBuilder.groupContainer()
|
||||
.withItems([appendToExistingEntryInTableCheckbox]).component();
|
||||
let logToTableContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({ flexFlow: 'row', justifyContent: 'space-between', width: 300 })
|
||||
.withItems([this.logToTableCheckbox, viewButton]).component();
|
||||
.withItems([this.logToTableCheckbox]).component();
|
||||
let logStepOutputHistoryCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({ label: 'Include step output in history' }).component();
|
||||
let runAsUserOptions = this.createRunAsUserOptions(view);
|
||||
.withProperties({ label: this.IncludeStepOutputHistoryLabel }).component();
|
||||
this.userInputBox = view.modelBuilder.inputBox()
|
||||
.withProperties({ inputType: 'text', width: '100%' }).component();
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[{
|
||||
component: this.successActionDropdown,
|
||||
title: JobStepDialog.SuccessAction
|
||||
title: this.SuccessActionLabel
|
||||
}, {
|
||||
component: retryFlexContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.failureActionDropdown,
|
||||
title: JobStepDialog.FailureAction
|
||||
title: this.FailureActionLabel
|
||||
}, {
|
||||
component: optionsGroup,
|
||||
title: 'Transact-SQL script (T-SQL)'
|
||||
title: this.TSQLScript
|
||||
}, {
|
||||
component: logToTableContainer,
|
||||
title: ''
|
||||
@@ -309,8 +313,8 @@ export class JobStepDialog {
|
||||
component: logStepOutputHistoryCheckbox,
|
||||
title: ''
|
||||
}, {
|
||||
component: runAsUserOptions,
|
||||
title: ''
|
||||
component: this.userInputBox,
|
||||
title: this.RunAsUserLabel
|
||||
}], {
|
||||
componentWidth: 400
|
||||
}).component();
|
||||
@@ -323,32 +327,37 @@ export class JobStepDialog {
|
||||
|
||||
private createRetryCounters(view) {
|
||||
this.retryAttemptsBox = view.modelBuilder.inputBox()
|
||||
.withValidation(component => component.value >= 0)
|
||||
.withProperties({
|
||||
inputType: 'number'
|
||||
})
|
||||
.component();
|
||||
.withValidation(component => component.value >= 0)
|
||||
.withProperties({
|
||||
inputType: 'number',
|
||||
width: '100%',
|
||||
placeHolder: '0'
|
||||
})
|
||||
.component();
|
||||
this.retryIntervalBox = view.modelBuilder.inputBox()
|
||||
.withValidation(component => component.value >= 0)
|
||||
.withProperties({
|
||||
inputType: 'number'
|
||||
inputType: 'number',
|
||||
width: '100%',
|
||||
placeHolder: '0'
|
||||
}).component();
|
||||
|
||||
let retryAttemptsContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[{
|
||||
component: this.retryAttemptsBox,
|
||||
title: 'Retry Attempts'
|
||||
}], {
|
||||
horizontal: false
|
||||
})
|
||||
[{
|
||||
component: this.retryAttemptsBox,
|
||||
title: this.RetryAttemptsLabel
|
||||
}], {
|
||||
horizontal: false,
|
||||
componentWidth: '100%'
|
||||
})
|
||||
.component();
|
||||
|
||||
let retryIntervalContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems(
|
||||
[{
|
||||
component: this.retryIntervalBox,
|
||||
title: 'Retry Interval (minutes)'
|
||||
title: this.RetryIntervalLabel
|
||||
}], {
|
||||
horizontal: false
|
||||
})
|
||||
@@ -362,7 +371,7 @@ export class JobStepDialog {
|
||||
}
|
||||
|
||||
private openFileBrowserDialog() {
|
||||
let fileBrowserTitle = JobStepDialog.FileBrowserDialogTitle + `${this.server}`;
|
||||
let fileBrowserTitle = this.FileBrowserDialogTitle + `${this.server}`;
|
||||
this.fileBrowserDialog = sqlops.window.modelviewdialog.createDialog(fileBrowserTitle);
|
||||
let fileBrowserTab = sqlops.window.modelviewdialog.createTab('File Browser');
|
||||
this.fileBrowserDialog.content = [fileBrowserTab];
|
||||
@@ -379,8 +388,8 @@ export class JobStepDialog {
|
||||
});
|
||||
this.fileTypeDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: 'All Files (*)',
|
||||
values: ['All Files (*)']
|
||||
value: this.AllFilesLabelString,
|
||||
values: [this.AllFilesLabelString]
|
||||
})
|
||||
.component();
|
||||
this.fileBrowserNameBox = view.modelBuilder.inputBox()
|
||||
@@ -392,13 +401,13 @@ export class JobStepDialog {
|
||||
title: ''
|
||||
}, {
|
||||
component: this.selectedPathTextBox,
|
||||
title: 'Selected path:'
|
||||
title: this.SelectedPathLabelString
|
||||
}, {
|
||||
component: this.fileTypeDropdown,
|
||||
title: 'Files of type:'
|
||||
title: this.FilesOfTypeLabelString
|
||||
}, {
|
||||
component: this.fileBrowserNameBox,
|
||||
title: 'File name:'
|
||||
title: this.FileNameLabelString
|
||||
}
|
||||
]).component();
|
||||
view.initializeModel(fileBrowserContainer);
|
||||
@@ -406,8 +415,8 @@ export class JobStepDialog {
|
||||
this.fileBrowserDialog.okButton.onClick(() => {
|
||||
this.outputFileNameBox.value = path.join(path.dirname(this.selectedPathTextBox.value), this.fileBrowserNameBox.value);
|
||||
});
|
||||
this.fileBrowserDialog.okButton.label = JobStepDialog.OkButtonText;
|
||||
this.fileBrowserDialog.cancelButton.label = JobStepDialog.CancelButtonText;
|
||||
this.fileBrowserDialog.okButton.label = this.OkButtonText;
|
||||
this.fileBrowserDialog.cancelButton.label = this.CancelButtonText;
|
||||
sqlops.window.modelviewdialog.openDialog(this.fileBrowserDialog);
|
||||
}
|
||||
|
||||
@@ -417,21 +426,15 @@ export class JobStepDialog {
|
||||
this.outputFileBrowserButton.onDidClick(() => this.openFileBrowserDialog());
|
||||
this.outputFileNameBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
width: '150px',
|
||||
width: 250,
|
||||
inputType: 'text'
|
||||
}).component();
|
||||
let outputViewButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
width: '50px',
|
||||
label: 'View'
|
||||
}).component();
|
||||
outputViewButton.enabled = false;
|
||||
let outputButtonContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
textAlign: 'right',
|
||||
width: 120
|
||||
}).withItems([this.outputFileBrowserButton, outputViewButton], { flex: '1 1 50%' }).component();
|
||||
width: '100%'
|
||||
}).withItems([this.outputFileBrowserButton], { flex: '1 1 50%' }).component();
|
||||
let outputFlexBox = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
@@ -441,7 +444,7 @@ export class JobStepDialog {
|
||||
}).component();
|
||||
this.appendToExistingFileCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: 'Append output to existing file'
|
||||
label: this.AppendOutputToFileLabel
|
||||
}).component();
|
||||
this.appendToExistingFileCheckbox.enabled = false;
|
||||
this.outputFileNameBox.onTextChanged((input) => {
|
||||
@@ -454,11 +457,11 @@ export class JobStepDialog {
|
||||
let outputFileForm = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: outputFlexBox,
|
||||
title: 'Output file'
|
||||
title: this.OutputFileNameLabel
|
||||
}, {
|
||||
component: this.appendToExistingFileCheckbox,
|
||||
title: ''
|
||||
}], { horizontal: true, componentWidth: 200 }).component();
|
||||
}], { horizontal: false, componentWidth: 200 }).component();
|
||||
return outputFileForm;
|
||||
}
|
||||
|
||||
@@ -471,8 +474,8 @@ export class JobStepDialog {
|
||||
this.model.databaseName = this.databaseDropdown.value as string;
|
||||
this.model.script = this.commandTextBox.value;
|
||||
this.model.successAction = this.successActionDropdown.value as string;
|
||||
this.model.retryAttempts = +this.retryAttemptsBox.value;
|
||||
this.model.retryInterval = +this.retryIntervalBox.value;
|
||||
this.model.retryAttempts = this.retryAttemptsBox.value ? +this.retryAttemptsBox.value : 0;
|
||||
this.model.retryInterval = +this.retryIntervalBox.value ? +this.retryIntervalBox.value : 0;
|
||||
this.model.failureAction = this.failureActionDropdown.value as string;
|
||||
this.model.outputFileName = this.outputFileNameBox.value;
|
||||
this.model.appendToLogFile = this.appendToExistingFileCheckbox.checked;
|
||||
|
||||
@@ -16,7 +16,8 @@ const localize = nls.loadMessageBundle();
|
||||
export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
|
||||
// Top level
|
||||
private static readonly DialogTitle: string = localize('createOperator.createOperator', 'Create Operator');
|
||||
private static readonly CreateDialogTitle: string = localize('createOperator.createOperator', 'Create Operator');
|
||||
private static readonly EditDialogTitle: string = localize('createOperator.editOperator', 'Edit Operator');
|
||||
private static readonly GeneralTabText: string = localize('createOperator.General', 'General');
|
||||
private static readonly NotificationsTabText: string = localize('createOperator.Notifications', 'Notifications');
|
||||
|
||||
@@ -32,6 +33,9 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
private static readonly PagerFridayCheckBoxLabel: string = localize('createOperator.PagerFridayCheckBox', 'Friday ');
|
||||
private static readonly PagerSaturdayCheckBoxLabel: string = localize('createOperator.PagerSaturdayCheckBox', 'Saturday');
|
||||
private static readonly PagerSundayCheckBoxLabel: string = localize('createOperator.PagerSundayCheckBox', 'Sunday');
|
||||
private static readonly WorkdayBeginLabel: string = localize('createOperator.workdayBegin', 'Workday begin');
|
||||
private static readonly WorkdayEndLabel: string = localize('createOperator.workdayEnd', 'Workday end');
|
||||
private static readonly PagerDutyScheduleLabel: string = localize('createOperator.PagerDutySchedule', 'Pager on duty schdule');
|
||||
|
||||
// Notifications tab strings
|
||||
private static readonly AlertsTableLabel: string = localize('createOperator.AlertListHeading', 'Alert list');
|
||||
@@ -65,8 +69,11 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
// Notification tab controls
|
||||
private alertsTable: sqlops.TableComponent;
|
||||
|
||||
constructor(ownerUri: string) {
|
||||
super(ownerUri, new OperatorData(ownerUri), OperatorDialog.DialogTitle);
|
||||
constructor(ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo = undefined) {
|
||||
super(
|
||||
ownerUri,
|
||||
new OperatorData(ownerUri, operatorInfo),
|
||||
operatorInfo ? OperatorDialog.EditDialogTitle : OperatorDialog.CreateDialogTitle);
|
||||
}
|
||||
|
||||
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
@@ -174,13 +181,13 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
this.weekdayPagerStartTimeInput = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
inputType: 'time',
|
||||
placeHolder: '08:00:00'
|
||||
placeHolder: '08:00:00',
|
||||
}).component();
|
||||
this.weekdayPagerStartTimeInput.enabled = false;
|
||||
let weekdayStartInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.weekdayPagerStartTimeInput,
|
||||
title: 'Workday begin'
|
||||
title: OperatorDialog.WorkdayBeginLabel
|
||||
}]).component();
|
||||
|
||||
this.weekdayPagerEndTimeInput = view.modelBuilder.inputBox()
|
||||
@@ -192,7 +199,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
let weekdayEndInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.weekdayPagerEndTimeInput,
|
||||
title: 'Workday end'
|
||||
title: OperatorDialog.WorkdayEndLabel
|
||||
}]).component();
|
||||
|
||||
this.pagerFridayCheckBox = view.modelBuilder.checkBox()
|
||||
@@ -216,7 +223,8 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
let pagerFridayCheckboxContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
alignItems: 'baseline'
|
||||
alignItems: 'baseline',
|
||||
width: '100%'
|
||||
}).withItems([this.pagerFridayCheckBox, weekdayStartInputContainer, weekdayEndInputContainer])
|
||||
.component();
|
||||
|
||||
@@ -245,7 +253,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
let saturdayStartInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.saturdayPagerStartTimeInput,
|
||||
title: 'Workday begin'
|
||||
title: OperatorDialog.WorkdayBeginLabel
|
||||
}]).component();
|
||||
|
||||
this.saturdayPagerEndTimeInput = view.modelBuilder.inputBox()
|
||||
@@ -257,7 +265,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
let saturdayEndInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.saturdayPagerEndTimeInput,
|
||||
title: 'Workday end'
|
||||
title: OperatorDialog.WorkdayEndLabel
|
||||
}]).component();
|
||||
|
||||
let pagerSaturdayCheckboxContainer = view.modelBuilder.flexContainer()
|
||||
@@ -292,7 +300,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
let sundayStartInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.sundayPagerStartTimeInput,
|
||||
title: 'Workday begin'
|
||||
title: OperatorDialog.WorkdayBeginLabel
|
||||
}]).component();
|
||||
|
||||
this.sundayPagerEndTimeInput = view.modelBuilder.inputBox()
|
||||
@@ -304,7 +312,7 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
let sundayEndInputContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.sundayPagerEndTimeInput,
|
||||
title: 'Workday end'
|
||||
title: OperatorDialog.WorkdayEndLabel
|
||||
}]).component();
|
||||
|
||||
let pagerSundayCheckboxContainer = view.modelBuilder.flexContainer()
|
||||
@@ -314,36 +322,6 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
}).withItems([this.pagerSundayCheckBox, sundayStartInputContainer, sundayEndInputContainer])
|
||||
.component();
|
||||
|
||||
let checkBoxContainer = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.pagerMondayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.pagerTuesdayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.pagerWednesdayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.pagerThursdayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: pagerFridayCheckboxContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: pagerSaturdayCheckboxContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: pagerSundayCheckboxContainer,
|
||||
title: ''
|
||||
}]).component();
|
||||
|
||||
let pagerContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row'
|
||||
}).withItems([checkBoxContainer])
|
||||
.component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.nameTextBox,
|
||||
@@ -358,8 +336,29 @@ export class OperatorDialog extends AgentDialog<OperatorData> {
|
||||
component: this.pagerEmailNameTextBox,
|
||||
title: OperatorDialog.PagerEmailNameTextLabel
|
||||
}, {
|
||||
component: pagerContainer,
|
||||
title: ''
|
||||
components: [{
|
||||
component: this.pagerMondayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.pagerTuesdayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.pagerWednesdayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: this.pagerThursdayCheckBox,
|
||||
title: ''
|
||||
}, {
|
||||
component: pagerFridayCheckboxContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: pagerSaturdayCheckboxContainer,
|
||||
title: ''
|
||||
}, {
|
||||
component: pagerSundayCheckboxContainer,
|
||||
title: ''
|
||||
}] ,
|
||||
title: OperatorDialog.PagerDutyScheduleLabel
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
@@ -4,18 +4,22 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { PickScheduleData } from '../data/pickScheduleData';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class PickScheduleDialog {
|
||||
|
||||
// TODO: localize
|
||||
// Top level
|
||||
private readonly DialogTitle: string = 'Job Schedules';
|
||||
private readonly OkButtonText: string = 'OK';
|
||||
private readonly CancelButtonText: string = 'Cancel';
|
||||
private readonly SchedulesTabText: string = 'Schedules';
|
||||
private readonly DialogTitle: string = localize('pickSchedule.jobSchedules', 'Job Schedules');
|
||||
private readonly OkButtonText: string = localize('pickSchedule.ok', 'OK');
|
||||
private readonly CancelButtonText: string = localize('pickSchedule.cancel', 'Cancel');
|
||||
private readonly ScheduleNameLabelText: string = localize('pickSchedule.scheduleName', 'Schedule Name');
|
||||
private readonly SchedulesLabelText: string = localize('pickSchedule.schedules', 'Schedules');
|
||||
|
||||
// UI Components
|
||||
private dialog: sqlops.window.modelviewdialog.Dialog;
|
||||
@@ -38,7 +42,6 @@ export class PickScheduleDialog {
|
||||
this.dialog.cancelButton.onClick(async () => await this.cancel());
|
||||
this.dialog.okButton.label = this.OkButtonText;
|
||||
this.dialog.cancelButton.label = this.CancelButtonText;
|
||||
|
||||
sqlops.window.modelviewdialog.openDialog(this.dialog);
|
||||
}
|
||||
|
||||
@@ -47,17 +50,17 @@ export class PickScheduleDialog {
|
||||
this.schedulesTable = view.modelBuilder.table()
|
||||
.withProperties({
|
||||
columns: [
|
||||
'Schedule Name'
|
||||
this.ScheduleNameLabelText
|
||||
],
|
||||
data: [],
|
||||
height: 600,
|
||||
width: 400
|
||||
height: '80em',
|
||||
width: '40em'
|
||||
}).component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.schedulesTable,
|
||||
title: 'Schedules'
|
||||
title: this.SchedulesLabelText
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
@@ -15,32 +15,60 @@ const localize = nls.loadMessageBundle();
|
||||
export class ProxyDialog extends AgentDialog<ProxyData> {
|
||||
|
||||
// Top level
|
||||
private static readonly DialogTitle: string = localize('createProxy.createAlert', 'Create Alert');
|
||||
private static readonly CreateDialogTitle: string = localize('createProxy.createProxy', 'Create Proxy');
|
||||
private static readonly EditDialogTitle: string = localize('createProxy.editProxy', 'Edit Proxy');
|
||||
private static readonly GeneralTabText: string = localize('createProxy.General', 'General');
|
||||
|
||||
// General tab strings
|
||||
private static readonly ProxyNameTextBoxLabel: string = localize('createProxy.ProxyName', 'Proxy name');
|
||||
private static readonly CredentialNameTextBoxLabel: string = localize('createProxy.CredentialName', 'Credential name');
|
||||
private static readonly DescriptionTextBoxLabel: string = localize('createProxy.Description', 'Description');
|
||||
private static readonly SubsystemsTableLabel: string = localize('createProxy.Subsystems', 'Subsystems');
|
||||
private static readonly SubsystemNameColumnLabel: string = localize('createProxy.SubsystemName', 'Subsystem');
|
||||
private static readonly SubsystemLabel: string = localize('createProxy.SubsystemName', 'Subsystem');
|
||||
private static readonly OperatingSystemLabel: string = localize('createProxy.OperatingSystem', 'Operating system (CmdExec)');
|
||||
private static readonly ReplicationSnapshotLabel: string = localize('createProxy.ReplicationSnapshot', 'Replication Snapshot');
|
||||
private static readonly ReplicationTransactionLogLabel: string = localize('createProxy.ReplicationTransactionLog', 'Replication Transaction-Log Reader');
|
||||
private static readonly ReplicationDistributorLabel: string = localize('createProxy.ReplicationDistributor', 'Replication Distributor');
|
||||
private static readonly ReplicationMergeLabel: string = localize('createProxy.ReplicationMerge', 'Replication Merge');
|
||||
private static readonly ReplicationQueueReaderLabel: string = localize('createProxy.ReplicationQueueReader', 'Replication Queue Reader');
|
||||
private static readonly SSASQueryLabel: string = localize('createProxy.SSASQueryLabel', 'SQL Server Analysis Services Query');
|
||||
private static readonly SSASCommandLabel: string = localize('createProxy.SSASCommandLabel', 'SQL Server Analysis Services Command');
|
||||
private static readonly SSISPackageLabel: string = localize('createProxy.SSISPackage', 'SQL Server Integration Services Package');
|
||||
private static readonly PowerShellLabel: string = localize('createProxy.PowerShell', 'PowerShell');
|
||||
private static readonly SubSystemHeadingLabel: string = localize('createProxy.subSystemHeading', 'Active to the following subsytems');
|
||||
|
||||
// UI Components
|
||||
private generalTab: sqlops.window.modelviewdialog.DialogTab;
|
||||
|
||||
// General tab controls
|
||||
private proxyNameTextBox: sqlops.InputBoxComponent;
|
||||
private credentialNameTextBox: sqlops.InputBoxComponent;
|
||||
private credentialNameDropDown: sqlops.DropDownComponent;
|
||||
private descriptionTextBox: sqlops.InputBoxComponent;
|
||||
private subsystemsTable: sqlops.TableComponent;
|
||||
private subsystemCheckBox: sqlops.CheckBoxComponent;
|
||||
private operatingSystemCheckBox: sqlops.CheckBoxComponent;
|
||||
private replicationSnapshotCheckBox: sqlops.CheckBoxComponent;
|
||||
private replicationTransactionLogCheckBox: sqlops.CheckBoxComponent;
|
||||
private replicationDistributorCheckBox: sqlops.CheckBoxComponent;
|
||||
private replicationMergeCheckbox: sqlops.CheckBoxComponent;
|
||||
private replicationQueueReaderCheckbox: sqlops.CheckBoxComponent;
|
||||
private sqlQueryCheckBox: sqlops.CheckBoxComponent;
|
||||
private sqlCommandCheckBox: sqlops.CheckBoxComponent;
|
||||
private sqlIntegrationServicesPackageCheckbox: sqlops.CheckBoxComponent;
|
||||
private powershellCheckBox: sqlops.CheckBoxComponent;
|
||||
|
||||
constructor(ownerUri: string) {
|
||||
super(ownerUri, new ProxyData(ownerUri), ProxyDialog.DialogTitle);
|
||||
private credentials: sqlops.CredentialInfo[];
|
||||
|
||||
constructor(ownerUri: string, proxyInfo: sqlops.AgentProxyInfo = undefined, credentials: sqlops.CredentialInfo[]) {
|
||||
super(
|
||||
ownerUri,
|
||||
new ProxyData(ownerUri, proxyInfo),
|
||||
proxyInfo ? ProxyDialog.EditDialogTitle : ProxyDialog.CreateDialogTitle);
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
|
||||
this.generalTab = sqlops.window.modelviewdialog.createTab(ProxyDialog.GeneralTabText);
|
||||
|
||||
|
||||
this.initializeGeneralTab();
|
||||
|
||||
this.dialog.content = [this.generalTab];
|
||||
@@ -49,43 +77,143 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
|
||||
private initializeGeneralTab() {
|
||||
this.generalTab.registerContent(async view => {
|
||||
|
||||
this.proxyNameTextBox = view.modelBuilder.inputBox().component();
|
||||
this.proxyNameTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({width: 420})
|
||||
.component();
|
||||
|
||||
this.credentialNameTextBox = view.modelBuilder.inputBox().component();
|
||||
|
||||
this.descriptionTextBox = view.modelBuilder.inputBox().component();
|
||||
|
||||
this.subsystemsTable = view.modelBuilder.table()
|
||||
this.credentialNameDropDown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
columns: [
|
||||
ProxyDialog.SubsystemNameColumnLabel
|
||||
],
|
||||
data: [],
|
||||
height: 500
|
||||
width: 432,
|
||||
value: '',
|
||||
editable: true,
|
||||
values: this.credentials.length > 0 ? this.credentials.map(c => c.name) : ['']
|
||||
})
|
||||
.component();
|
||||
|
||||
this.descriptionTextBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
width: 420,
|
||||
multiline: true,
|
||||
height: 300
|
||||
})
|
||||
.component();
|
||||
|
||||
this.subsystemCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.SubsystemLabel
|
||||
}).component();
|
||||
|
||||
this.subsystemCheckBox.onChanged(() => {
|
||||
if (this.subsystemCheckBox.checked) {
|
||||
this.operatingSystemCheckBox.checked = true;
|
||||
this.replicationSnapshotCheckBox.checked = true;
|
||||
this.replicationTransactionLogCheckBox.checked = true;
|
||||
this.replicationDistributorCheckBox.checked = true;
|
||||
this.replicationMergeCheckbox.checked = true;
|
||||
this.replicationQueueReaderCheckbox.checked = true;
|
||||
this.sqlQueryCheckBox.checked = true;
|
||||
this.sqlCommandCheckBox.checked = true;
|
||||
this.sqlIntegrationServicesPackageCheckbox.checked = true;
|
||||
this.powershellCheckBox.checked = true;
|
||||
} else {
|
||||
this.operatingSystemCheckBox.checked = false;
|
||||
this.replicationSnapshotCheckBox.checked = false;
|
||||
this.replicationTransactionLogCheckBox.checked = false;
|
||||
this.replicationDistributorCheckBox.checked = false;
|
||||
this.replicationMergeCheckbox.checked = false;
|
||||
this.replicationQueueReaderCheckbox.checked = false;
|
||||
this.sqlQueryCheckBox.checked = false;
|
||||
this.sqlCommandCheckBox.checked = false;
|
||||
this.sqlIntegrationServicesPackageCheckbox.checked = false;
|
||||
this.powershellCheckBox.checked = false;
|
||||
}
|
||||
});
|
||||
|
||||
this.operatingSystemCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.OperatingSystemLabel
|
||||
}).component();
|
||||
|
||||
this.replicationSnapshotCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.ReplicationSnapshotLabel
|
||||
}).component();
|
||||
|
||||
this.replicationTransactionLogCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.ReplicationTransactionLogLabel
|
||||
}).component();
|
||||
|
||||
this.replicationDistributorCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.ReplicationDistributorLabel
|
||||
}).component();
|
||||
|
||||
this.replicationMergeCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.ReplicationMergeLabel
|
||||
}).component();
|
||||
|
||||
this.replicationQueueReaderCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.ReplicationQueueReaderLabel
|
||||
}).component();
|
||||
|
||||
this.sqlQueryCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.SSASQueryLabel
|
||||
}).component();
|
||||
|
||||
this.sqlCommandCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.SSASCommandLabel
|
||||
}).component();
|
||||
|
||||
this.sqlIntegrationServicesPackageCheckbox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.SSISPackageLabel
|
||||
}).component();
|
||||
|
||||
this.powershellCheckBox = view.modelBuilder.checkBox()
|
||||
.withProperties({
|
||||
label: ProxyDialog.PowerShellLabel
|
||||
}).component();
|
||||
|
||||
let checkBoxContainer = view.modelBuilder.groupContainer()
|
||||
.withItems([this.operatingSystemCheckBox, this.replicationSnapshotCheckBox,
|
||||
this.replicationTransactionLogCheckBox, this.replicationDistributorCheckBox, this.replicationMergeCheckbox,
|
||||
this.replicationQueueReaderCheckbox, this.sqlQueryCheckBox, this.sqlCommandCheckBox, this.sqlIntegrationServicesPackageCheckbox,
|
||||
this.powershellCheckBox])
|
||||
.component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.proxyNameTextBox,
|
||||
title: ProxyDialog.ProxyNameTextBoxLabel
|
||||
}, {
|
||||
component: this.credentialNameTextBox,
|
||||
component: this.credentialNameDropDown,
|
||||
title: ProxyDialog.CredentialNameTextBoxLabel
|
||||
}, {
|
||||
component: this.descriptionTextBox,
|
||||
title: ProxyDialog.DescriptionTextBoxLabel
|
||||
}, {
|
||||
component: this.subsystemsTable,
|
||||
title: ProxyDialog.SubsystemsTableLabel
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
}]).withLayout({ width: 420 }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
this.proxyNameTextBox.value = this.model.accountName;
|
||||
this.credentialNameDropDown.value = this.model.credentialName;
|
||||
this.descriptionTextBox.value = this.model.description;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
protected updateModel() {
|
||||
this.model.accountName = this.proxyNameTextBox.value;
|
||||
this.model.credentialName = this.credentialNameTextBox.value;
|
||||
this.model.credentialName = this.credentialNameDropDown.value as string;
|
||||
this.model.credentialId = this.credentials.find(
|
||||
c => c.name === this.model.credentialName).id;
|
||||
this.model.credentialIdentity = this.credentials.find(
|
||||
c => c.name === this.model.credentialName).identity;
|
||||
this.model.description = this.descriptionTextBox.value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,17 +4,21 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { ScheduleData } from '../data/scheduleData';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export class ScheduleDialog {
|
||||
|
||||
// Top level
|
||||
private readonly DialogTitle: string = 'New Schedule';
|
||||
private readonly OkButtonText: string = 'OK';
|
||||
private readonly CancelButtonText: string = 'Cancel';
|
||||
private readonly DialogTitle: string = localize('scheduleDialog.newSchedule', 'New Schedule');
|
||||
private readonly OkButtonText: string = localize('scheduleDialog.ok', 'OK');
|
||||
private readonly CancelButtonText: string = localize('scheduleDialog.cancel', 'Cancel');
|
||||
private readonly ScheduleNameText: string = localize('scheduleDialog.scheduleName', 'Schedule Name');
|
||||
private readonly SchedulesLabelText: string = localize('scheduleDialog.schedules', 'Schedules');
|
||||
|
||||
// UI Components
|
||||
private dialog: sqlops.window.modelviewdialog.Dialog;
|
||||
@@ -46,7 +50,7 @@ export class ScheduleDialog {
|
||||
this.schedulesTable = view.modelBuilder.table()
|
||||
.withProperties({
|
||||
columns: [
|
||||
'Schedule Name'
|
||||
this.ScheduleNameText
|
||||
],
|
||||
data: [],
|
||||
height: 600,
|
||||
@@ -56,7 +60,7 @@ export class ScheduleDialog {
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.schedulesTable,
|
||||
title: 'Schedules'
|
||||
title: this.SchedulesLabelText
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as vscode from 'vscode';
|
||||
import { AlertDialog } from './dialogs/alertDialog';
|
||||
@@ -12,6 +14,8 @@ import { ProxyDialog } from './dialogs/proxyDialog';
|
||||
import { JobStepDialog } from './dialogs/jobStepDialog';
|
||||
import { PickScheduleDialog } from './dialogs/pickScheduleDialog';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
/**
|
||||
* The main controller class that initializes the extension
|
||||
*/
|
||||
@@ -23,12 +27,17 @@ export class MainController {
|
||||
this._context = context;
|
||||
}
|
||||
|
||||
public static showNotYetImplemented(): void {
|
||||
vscode.window.showInformationMessage(
|
||||
localize('mainController.notImplemented', "This feature is under development. Check-out the latest insiders build if you'd like to try out the most recent changes!"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the extension
|
||||
*/
|
||||
public activate(): void {
|
||||
vscode.commands.registerCommand('agent.openCreateJobDialog', (ownerUri: string) => {
|
||||
let dialog = new JobDialog(ownerUri);
|
||||
vscode.commands.registerCommand('agent.openJobDialog', (ownerUri: string, jobInfo: sqlops.AgentJobInfo) => {
|
||||
let dialog = new JobDialog(ownerUri, jobInfo);
|
||||
dialog.openDialog();
|
||||
});
|
||||
vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, jobId: string, server: string, stepId: number) => {
|
||||
@@ -39,17 +48,19 @@ export class MainController {
|
||||
let dialog = new PickScheduleDialog(ownerUri);
|
||||
dialog.showDialog();
|
||||
});
|
||||
vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, alertInfo: sqlops.AgentAlertInfo) => {
|
||||
let dialog = new AlertDialog(ownerUri, alertInfo);
|
||||
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.openCreateOperatorDialog', (ownerUri: string) => {
|
||||
let dialog = new OperatorDialog(ownerUri);
|
||||
vscode.commands.registerCommand('agent.openOperatorDialog', (ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo) => {
|
||||
let dialog = new OperatorDialog(ownerUri, operatorInfo);
|
||||
dialog.openDialog();
|
||||
});
|
||||
vscode.commands.registerCommand('agent.openCreateProxyDialog', (ownerUri: string) => {
|
||||
let dialog = new ProxyDialog(ownerUri);
|
||||
dialog.openDialog();
|
||||
vscode.commands.registerCommand('agent.openProxyDialog', (ownerUri: string, proxyInfo: sqlops.AgentProxyInfo, credentials: sqlops.CredentialInfo[]) => {
|
||||
//@TODO: reenable create proxy after snapping July release (7/14/18)
|
||||
// let dialog = new ProxyDialog(ownerUri, proxyInfo, credentials);
|
||||
// dialog.openDialog();
|
||||
MainController.showNotYetImplemented();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ const testOwnerUri = 'agent://testuri';
|
||||
suite('Agent extension', () => {
|
||||
test('Create Job Data', async () => {
|
||||
let testAgentService = new TestAgentService();
|
||||
let data = new JobData(testOwnerUri, testAgentService);
|
||||
let data = new JobData(testOwnerUri, undefined, testAgentService);
|
||||
data.save();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -86,6 +86,11 @@ export class TestAgentService implements sqlops.AgentServicesProvider {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Agent Credential method
|
||||
getCredentials(ownerUri: string): Thenable<sqlops.GetCredentialsResult> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Job Schedule management methods
|
||||
getJobSchedules(ownerUri: string): Thenable<sqlops.AgentJobSchedulesResult> {
|
||||
return undefined;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
|
||||
"version": "1.5.0-alpha.4",
|
||||
"version": "1.5.0-alpha.9",
|
||||
"downloadFileNames": {
|
||||
"Windows_86": "win-x86-netcoreapp2.1.zip",
|
||||
"Windows_64": "win-x64-netcoreapp2.1.zip",
|
||||
|
||||
@@ -148,6 +148,11 @@ export interface DeleteAgentProxyParams {
|
||||
proxy: sqlops.AgentProxyInfo;
|
||||
}
|
||||
|
||||
// Agent Credentials parameters
|
||||
export interface GetCredentialsParams {
|
||||
ownerUri: string;
|
||||
}
|
||||
|
||||
// Job Schedule management parameters
|
||||
export interface AgentJobScheduleParams {
|
||||
ownerUri: string;
|
||||
@@ -262,6 +267,11 @@ export namespace DeleteAgentProxyRequest {
|
||||
export const type = new RequestType<DeleteAgentProxyParams, sqlops.ResultStatus, void, void>('agent/deleteproxy');
|
||||
}
|
||||
|
||||
// Agent Credentials request
|
||||
export namespace AgentCredentialsRequest {
|
||||
export const type = new RequestType<GetCredentialsParams, sqlops.GetCredentialsResult, void, void>('security/credentials');
|
||||
}
|
||||
|
||||
// Job Schedules requests
|
||||
export namespace AgentJobSchedulesRequest {
|
||||
export const type = new RequestType<AgentJobScheduleParams, sqlops.AgentJobSchedulesResult, void, void>('agent/schedules');
|
||||
|
||||
@@ -438,6 +438,22 @@ export class AgentServicesFeature extends SqlOpsFeature<undefined> {
|
||||
);
|
||||
};
|
||||
|
||||
// Agent Credential Method
|
||||
let getCredentials = (ownerUri: string): Thenable<sqlops.GetCredentialsResult> => {
|
||||
let params: contracts.GetCredentialsParams = {
|
||||
ownerUri: ownerUri
|
||||
};
|
||||
let requestType = contracts.AgentCredentialsRequest.type;
|
||||
return client.sendRequest(requestType, params).then(
|
||||
r => r,
|
||||
e => {
|
||||
client.logFailedRequest(requestType, e);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// Job Schedule management methods
|
||||
let getJobSchedules = (ownerUri: string): Thenable<sqlops.AgentJobSchedulesResult> => {
|
||||
let params: contracts.AgentJobScheduleParams = {
|
||||
@@ -532,6 +548,7 @@ export class AgentServicesFeature extends SqlOpsFeature<undefined> {
|
||||
createProxy,
|
||||
updateProxy,
|
||||
deleteProxy,
|
||||
getCredentials,
|
||||
getJobSchedules,
|
||||
createJobSchedule,
|
||||
updateJobSchedule,
|
||||
|
||||
@@ -44,22 +44,6 @@ export class Telemetry {
|
||||
private static platformInformation: PlatformInformation;
|
||||
private static disabled: boolean;
|
||||
|
||||
// Get the unique ID for the current user of the extension
|
||||
public static getUserId(): Promise<string> {
|
||||
return new Promise<string>(resolve => {
|
||||
// Generate the user id if it has not been created already
|
||||
if (typeof this.userId === 'undefined') {
|
||||
let id = Utils.generateUserId();
|
||||
id.then(newId => {
|
||||
this.userId = newId;
|
||||
resolve(this.userId);
|
||||
});
|
||||
} else {
|
||||
resolve(this.userId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static getPlatformInformation(): Promise<PlatformInformation> {
|
||||
if (this.platformInformation) {
|
||||
return Promise.resolve(this.platformInformation);
|
||||
@@ -143,8 +127,7 @@ export class Telemetry {
|
||||
}
|
||||
|
||||
// Augment the properties structure with additional common properties before sending
|
||||
Promise.all([this.getUserId(), this.getPlatformInformation()]).then(() => {
|
||||
properties['userId'] = this.userId;
|
||||
Promise.all([this.getPlatformInformation()]).then(() => {
|
||||
properties['distribution'] = (this.platformInformation && this.platformInformation.distribution) ?
|
||||
`${this.platformInformation.distribution.name}, ${this.platformInformation.distribution.version}` : '';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sqlops",
|
||||
"version": "0.31.2",
|
||||
"version": "0.31.3",
|
||||
"distro": "8c3e97e3425cc9814496472ab73e076de2ba99ee",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
@@ -60,7 +60,7 @@
|
||||
"reflect-metadata": "^0.1.8",
|
||||
"rxjs": "5.4.0",
|
||||
"semver": "4.3.6",
|
||||
"slickgrid": "github:anthonydresser/SlickGrid#2.3.22",
|
||||
"slickgrid": "github:anthonydresser/SlickGrid#2.3.23",
|
||||
"spdlog": "0.6.0",
|
||||
"sudo-prompt": "^8.0.0",
|
||||
"svg.js": "^2.2.5",
|
||||
|
||||
@@ -285,7 +285,6 @@ export default class MainController implements vscode.Disposable {
|
||||
tab1.registerContent(async (view) => {
|
||||
await this.getTabContent(view, customButton1, customButton2, 400);
|
||||
});
|
||||
|
||||
sqlops.window.modelviewdialog.openDialog(dialog);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,13 +63,13 @@ export class InputBox extends vsInputBox {
|
||||
this.enabledInputBorder = this.inputBorder;
|
||||
this.disabledInputBackground = styles.disabledInputBackground;
|
||||
this.disabledInputForeground = styles.disabledInputForeground;
|
||||
this.updateInputEnabledDisabledColors();
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
public enable(): void {
|
||||
super.enable();
|
||||
this.inputBackground = this.enabledInputBackground;
|
||||
this.inputForeground = this.enabledInputForeground;
|
||||
this.inputBorder = this.enabledInputBorder;
|
||||
this.updateInputEnabledDisabledColors();
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
@@ -89,9 +89,7 @@ export class InputBox extends vsInputBox {
|
||||
|
||||
public disable(): void {
|
||||
super.disable();
|
||||
this.inputBackground = this.disabledInputBackground;
|
||||
this.inputForeground = this.disabledInputForeground;
|
||||
this.inputBorder = this.disabledInputBorder;
|
||||
this.updateInputEnabledDisabledColors();
|
||||
this.applyStyles();
|
||||
}
|
||||
|
||||
@@ -121,4 +119,11 @@ export class InputBox extends vsInputBox {
|
||||
super.showMessage(message, force);
|
||||
}
|
||||
}
|
||||
|
||||
private updateInputEnabledDisabledColors(): void {
|
||||
let enabled = this.isEnabled();
|
||||
this.inputBackground = enabled ? this.enabledInputBackground : this.disabledInputBackground;
|
||||
this.inputForeground = enabled ? this.enabledInputForeground : this.disabledInputForeground;
|
||||
this.inputBorder = enabled ? this.enabledInputBorder : this.disabledInputBorder;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export function appendRow(container: Builder, label: string, labelClass: string,
|
||||
container.element('tr', {}, (rowContainer) => {
|
||||
rowContainer.element('td', { class: labelClass }, (labelCellContainer) => {
|
||||
labelCellContainer.div({}, (labelContainer) => {
|
||||
labelContainer.innerHtml(label);
|
||||
labelContainer.text(label);
|
||||
});
|
||||
});
|
||||
rowContainer.element('td', { class: cellContainerClass }, (inputCellContainer) => {
|
||||
|
||||
@@ -170,7 +170,7 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
}
|
||||
modalHeader.div({ class: 'modal-title' }, (modalTitle) => {
|
||||
this._modalTitle = modalTitle;
|
||||
modalTitle.innerHtml(this._title);
|
||||
modalTitle.text(this._title);
|
||||
});
|
||||
});
|
||||
parts.push(this._modalHeaderSection.getHTMLElement());
|
||||
@@ -433,7 +433,7 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
*/
|
||||
protected set title(title: string) {
|
||||
if (this._title !== undefined) {
|
||||
this._modalTitle.innerHtml(title);
|
||||
this._modalTitle.text(title);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
import { Component, Input, ContentChild, OnDestroy, TemplateRef, ChangeDetectorRef, forwardRef, Inject } from '@angular/core';
|
||||
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
export abstract class TabChild {
|
||||
export abstract class TabChild extends Disposable {
|
||||
public abstract layout(): void;
|
||||
}
|
||||
|
||||
@@ -19,7 +20,7 @@ export abstract class TabChild {
|
||||
`
|
||||
})
|
||||
export class TabComponent implements OnDestroy {
|
||||
@ContentChild(TabChild) private _child: TabChild;
|
||||
private _child: TabChild;
|
||||
@ContentChild(TemplateRef) templateRef;
|
||||
@Input() public title: string;
|
||||
@Input() public canClose: boolean;
|
||||
@@ -29,19 +30,30 @@ export class TabComponent implements OnDestroy {
|
||||
@Input() public identifier: string;
|
||||
@Input() private visibilityType: 'if' | 'visibility' = 'if';
|
||||
private rendered = false;
|
||||
private destroyed: boolean = false;
|
||||
|
||||
|
||||
@ContentChild(TabChild) private set child(tab: TabChild) {
|
||||
this._child = tab;
|
||||
if (this.active && this._child) {
|
||||
this._child.layout();
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef
|
||||
) { }
|
||||
|
||||
public set active(val: boolean) {
|
||||
this._active = val;
|
||||
if (this.active) {
|
||||
this.rendered = true;
|
||||
}
|
||||
this._cd.detectChanges();
|
||||
if (this.active && this._child) {
|
||||
this._child.layout();
|
||||
if (!this.destroyed) {
|
||||
this._active = val;
|
||||
if (this.active) {
|
||||
this.rendered = true;
|
||||
}
|
||||
this._cd.detectChanges();
|
||||
if (this.active && this._child) {
|
||||
this._child.layout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +62,7 @@ export class TabComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.destroyed = true;
|
||||
if (this.actions && this.actions.length > 0) {
|
||||
this.actions.forEach((action) => action.dispose());
|
||||
}
|
||||
@@ -74,6 +87,8 @@ export class TabComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
public layout() {
|
||||
this._child.layout();
|
||||
if (this._child) {
|
||||
this._child.layout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
{
|
||||
border: 1px solid #BFBDBD;
|
||||
font-size: 8pt;
|
||||
height: 400px;
|
||||
height: 250px;
|
||||
margin-top: 6px;
|
||||
overflow: scroll;
|
||||
padding: 4px;
|
||||
|
||||
@@ -13,3 +13,6 @@ export const SerializationDisabled = 'Saving results into different format disab
|
||||
*/
|
||||
export const RestoreFeatureName = 'restore';
|
||||
export const BackupFeatureName = 'backup';
|
||||
|
||||
export const MssqlProviderId = 'MSSQL';
|
||||
|
||||
|
||||
@@ -81,6 +81,15 @@
|
||||
content: url("status_info.svg");
|
||||
}
|
||||
|
||||
.vs .icon.help {
|
||||
content: url("help.svg");
|
||||
}
|
||||
|
||||
.vs-dark .icon.help,
|
||||
.hc-black .icon.help {
|
||||
content: url("help_inverse.svg");
|
||||
}
|
||||
|
||||
.vs .icon.success,
|
||||
.vs-dark .icon.success,
|
||||
.hc-black .icon.success {
|
||||
|
||||
1
src/sql/media/icons/help.svg
Normal file
1
src/sql/media/icons/help.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>help_16x16</title><path d="M10.13.45A8.14,8.14,0,0,1,12,1.23a8,8,0,0,1,1.62,1.21A7.8,7.8,0,0,1,14.91,4a7.59,7.59,0,0,1,.81,1.85,7.6,7.6,0,0,1,0,4.12,7.59,7.59,0,0,1-.81,1.85,7.8,7.8,0,0,1-1.25,1.57A8,8,0,0,1,12,14.62a8.2,8.2,0,0,1-8.08,0,8,8,0,0,1-1.62-1.21,7.8,7.8,0,0,1-1.25-1.57A7.63,7.63,0,0,1,.28,10a7.6,7.6,0,0,1,0-4.12A7.63,7.63,0,0,1,1.09,4,7.8,7.8,0,0,1,2.34,2.44,8,8,0,0,1,4,1.23,8.26,8.26,0,0,1,10.13.45Zm-.27,14a7.17,7.17,0,0,0,1.67-.69,7,7,0,0,0,1.41-1.06,6.75,6.75,0,0,0,1.8-3,6.59,6.59,0,0,0,0-3.6,6.75,6.75,0,0,0-1.8-3,7,7,0,0,0-1.41-1.06,7.17,7.17,0,0,0-1.67-.69,7.21,7.21,0,0,0-3.72,0,7.17,7.17,0,0,0-1.67.69A7,7,0,0,0,3.05,3.13,6.82,6.82,0,0,0,2,4.5a6.72,6.72,0,0,0-.71,1.62,6.59,6.59,0,0,0,0,3.6A6.72,6.72,0,0,0,2,11.35a6.82,6.82,0,0,0,1.09,1.37,7,7,0,0,0,1.41,1.06,7.17,7.17,0,0,0,1.67.69,7.21,7.21,0,0,0,3.72,0ZM9,4a2.75,2.75,0,0,1,.85.56,2.61,2.61,0,0,1,.57.82,2.44,2.44,0,0,1,.21,1,2.08,2.08,0,0,1-.16.85,2.82,2.82,0,0,1-.4.65,4.28,4.28,0,0,1-.51.53c-.18.16-.36.32-.51.48a2.55,2.55,0,0,0-.4.51,1.19,1.19,0,0,0-.16.61v.52H7.46V10a2.09,2.09,0,0,1,.16-.85A2.86,2.86,0,0,1,8,8.5,4.28,4.28,0,0,1,8.54,8c.18-.16.36-.32.51-.48A2.51,2.51,0,0,0,9.45,7a1.18,1.18,0,0,0,.16-.61,1.49,1.49,0,0,0-.13-.61,1.56,1.56,0,0,0-.34-.49A1.63,1.63,0,0,0,8,4.81a1.63,1.63,0,0,0-1.14.45,1.57,1.57,0,0,0-.34.49,1.49,1.49,0,0,0-.13.61H5.32a2.41,2.41,0,0,1,.21-1,2.68,2.68,0,0,1,.58-.82A2.77,2.77,0,0,1,7,4a2.62,2.62,0,0,1,1-.21A2.65,2.65,0,0,1,9,4ZM8.54,12.6H7.46v-1H8.54Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
1
src/sql/media/icons/help_inverse.svg
Normal file
1
src/sql/media/icons/help_inverse.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>help_inverse_16x16</title><path class="cls-1" d="M10.13.45A8.14,8.14,0,0,1,12,1.23a8,8,0,0,1,1.62,1.21A7.8,7.8,0,0,1,14.91,4a7.59,7.59,0,0,1,.81,1.85,7.6,7.6,0,0,1,0,4.12,7.59,7.59,0,0,1-.81,1.85,7.8,7.8,0,0,1-1.25,1.57A8,8,0,0,1,12,14.62a8.2,8.2,0,0,1-8.08,0,8,8,0,0,1-1.62-1.21,7.8,7.8,0,0,1-1.25-1.57A7.63,7.63,0,0,1,.28,10a7.6,7.6,0,0,1,0-4.12A7.63,7.63,0,0,1,1.09,4,7.8,7.8,0,0,1,2.34,2.44,8,8,0,0,1,4,1.23,8.26,8.26,0,0,1,10.13.45Zm-.27,14a7.17,7.17,0,0,0,1.67-.69,7,7,0,0,0,1.41-1.06,6.75,6.75,0,0,0,1.8-3,6.59,6.59,0,0,0,0-3.6,6.75,6.75,0,0,0-1.8-3,7,7,0,0,0-1.41-1.06,7.17,7.17,0,0,0-1.67-.69,7.21,7.21,0,0,0-3.72,0,7.17,7.17,0,0,0-1.67.69A7,7,0,0,0,3.05,3.13,6.82,6.82,0,0,0,2,4.5a6.72,6.72,0,0,0-.71,1.62,6.59,6.59,0,0,0,0,3.6A6.72,6.72,0,0,0,2,11.35a6.82,6.82,0,0,0,1.09,1.37,7,7,0,0,0,1.41,1.06,7.17,7.17,0,0,0,1.67.69,7.21,7.21,0,0,0,3.72,0ZM9,4a2.75,2.75,0,0,1,.85.56,2.61,2.61,0,0,1,.57.82,2.44,2.44,0,0,1,.21,1,2.08,2.08,0,0,1-.16.85,2.82,2.82,0,0,1-.4.65,4.28,4.28,0,0,1-.51.53c-.18.16-.36.32-.51.48a2.55,2.55,0,0,0-.4.51,1.19,1.19,0,0,0-.16.61v.52H7.46V10a2.09,2.09,0,0,1,.16-.85A2.86,2.86,0,0,1,8,8.5,4.28,4.28,0,0,1,8.54,8c.18-.16.36-.32.51-.48A2.51,2.51,0,0,0,9.45,7a1.18,1.18,0,0,0,.16-.61,1.49,1.49,0,0,0-.13-.61,1.56,1.56,0,0,0-.34-.49A1.63,1.63,0,0,0,8,4.81a1.63,1.63,0,0,0-1.14.45,1.57,1.57,0,0,0-.34.49,1.49,1.49,0,0,0-.13.61H5.32a2.41,2.41,0,0,1,.21-1,2.68,2.68,0,0,1,.58-.82A2.77,2.77,0,0,1,7,4a2.62,2.62,0,0,1,1-.21A2.65,2.65,0,0,1,9,4ZM8.54,12.6H7.46v-1H8.54Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -131,7 +131,7 @@ export class AccountDialog extends Modal {
|
||||
this._noaccountViewContainer = DOM.$('div.no-account-view');
|
||||
let noAccountTitle = DOM.append(this._noaccountViewContainer, DOM.$('.no-account-view-label'));
|
||||
let noAccountLabel = localize('accountDialog.noAccountLabel', 'There is no linked account. Please add an account.');
|
||||
noAccountTitle.innerHTML = noAccountLabel;
|
||||
noAccountTitle.innerText = noAccountLabel;
|
||||
|
||||
// Show the add account button for the first provider
|
||||
// Todo: If we have more than 1 provider, need to show all add account buttons for all providers
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IConnectionProfile } from 'sqlops';
|
||||
|
||||
export class ConnectionContextkey implements IContextKey<IConnectionProfile> {
|
||||
export class ConnectionContextKey implements IContextKey<IConnectionProfile> {
|
||||
|
||||
static Provider = new RawContextKey<string>('connectionProvider', undefined);
|
||||
static Server = new RawContextKey<string>('serverName', undefined);
|
||||
@@ -23,10 +23,10 @@ export class ConnectionContextkey implements IContextKey<IConnectionProfile> {
|
||||
constructor(
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
this._providerKey = ConnectionContextkey.Provider.bindTo(contextKeyService);
|
||||
this._serverKey = ConnectionContextkey.Server.bindTo(contextKeyService);
|
||||
this._databaseKey = ConnectionContextkey.Database.bindTo(contextKeyService);
|
||||
this._connectionKey = ConnectionContextkey.Connection.bindTo(contextKeyService);
|
||||
this._providerKey = ConnectionContextKey.Provider.bindTo(contextKeyService);
|
||||
this._serverKey = ConnectionContextKey.Server.bindTo(contextKeyService);
|
||||
this._databaseKey = ConnectionContextKey.Database.bindTo(contextKeyService);
|
||||
this._connectionKey = ConnectionContextKey.Connection.bindTo(contextKeyService);
|
||||
}
|
||||
|
||||
set(value: IConnectionProfile) {
|
||||
|
||||
@@ -174,7 +174,7 @@ export interface IConnectionManagementService {
|
||||
|
||||
disconnectEditor(owner: IConnectableInput, force?: boolean): Promise<boolean>;
|
||||
|
||||
disconnect(connection: ConnectionProfile): Promise<void>;
|
||||
disconnect(connection: IConnectionProfile): Promise<void>;
|
||||
|
||||
disconnect(ownerUri: string): Promise<void>;
|
||||
|
||||
@@ -208,7 +208,7 @@ export interface IConnectionManagementService {
|
||||
*/
|
||||
cancelEditorConnection(owner: IConnectableInput): Thenable<boolean>;
|
||||
|
||||
showDashboard(connection: ConnectionProfile): Thenable<boolean>;
|
||||
showDashboard(connection: IConnectionProfile): Thenable<boolean>;
|
||||
|
||||
closeDashboard(uri: string): void;
|
||||
|
||||
@@ -216,7 +216,7 @@ export interface IConnectionManagementService {
|
||||
|
||||
hasRegisteredServers(): boolean;
|
||||
|
||||
canChangeConnectionConfig(profile: ConnectionProfile, newGroupID: string): boolean;
|
||||
canChangeConnectionConfig(profile: IConnectionProfile, newGroupID: string): boolean;
|
||||
|
||||
getTabColorForUri(uri: string): string;
|
||||
|
||||
|
||||
@@ -553,7 +553,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
});
|
||||
}
|
||||
|
||||
public showDashboard(connection: ConnectionProfile): Thenable<boolean> {
|
||||
public showDashboard(connection: IConnectionProfile): Thenable<boolean> {
|
||||
return this.showDashboardForConnectionManagementInfo(connection);
|
||||
}
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@ export class ConnectionStore {
|
||||
return connectionProfile;
|
||||
} else {
|
||||
return undefined;
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ export class ConnectionStore {
|
||||
list.unshift(savedProfile);
|
||||
|
||||
let newList = list.map(c => {
|
||||
let connectionProfile = c ? c.toIConnectionProfile() : undefined;;
|
||||
let connectionProfile = c ? c.toIConnectionProfile() : undefined;
|
||||
return connectionProfile;
|
||||
});
|
||||
return newList.filter(n => n !== undefined);
|
||||
@@ -372,7 +372,7 @@ export class ConnectionStore {
|
||||
});
|
||||
|
||||
let newList = list.map(c => {
|
||||
let connectionProfile = c ? c.toIConnectionProfile() : undefined;;
|
||||
let connectionProfile = c ? c.toIConnectionProfile() : undefined;
|
||||
return connectionProfile;
|
||||
});
|
||||
return newList.filter(n => n !== undefined);
|
||||
|
||||
@@ -339,9 +339,9 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
if (!platform.isWindows && types.isString(message) && message.toLowerCase().includes('kerberos') && message.toLowerCase().includes('kinit')) {
|
||||
message = [
|
||||
localize('kerberosErrorStart', "Connection failed due to Kerberos error."),
|
||||
localize('kerberosHelpLink', " Help configuring Kerberos is available at ") + helpLink,
|
||||
localize('kerberosKinit', " If you have previously connected you may need to re-run kinit.")
|
||||
].join('<br/>');
|
||||
localize('kerberosHelpLink', "Help configuring Kerberos is available at {0}", helpLink),
|
||||
localize('kerberosKinit', "If you have previously connected you may need to re-run kinit.")
|
||||
].join('\r\n');
|
||||
actions.push(new Action('Kinit', 'Run kinit', null, true, () => {
|
||||
this._connectionDialog.close();
|
||||
this._clipboardService.writeText('kinit\r');
|
||||
|
||||
@@ -32,22 +32,10 @@ export abstract class DashboardTab extends TabChild implements OnDestroy {
|
||||
public enableEdit(): void {
|
||||
// no op
|
||||
}
|
||||
|
||||
private _toDispose: IDisposable[] = [];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._toDispose = dispose(this._toDispose);
|
||||
}
|
||||
|
||||
protected _register<T extends IDisposable>(t: T): T {
|
||||
this._toDispose.push(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export class DashboardErrorContainer extends DashboardTab implements AfterViewIn
|
||||
|
||||
ngAfterViewInit() {
|
||||
let errorMessage = this._errorMessageContainer.nativeElement as HTMLElement;
|
||||
errorMessage.innerHTML = nls.localize('dashboardNavSection_loadTabError', 'The "{0}" section has invalid content. Please contact extension owner.', this.tab.title);
|
||||
errorMessage.innerText = nls.localize('dashboardNavSection_loadTabError', 'The "{0}" section has invalid content. Please contact extension owner.', this.tab.title);
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { DashboardModule } from './dashboard.module';
|
||||
import { bootstrapAngular } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { IDashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams';
|
||||
import { DASHBOARD_SELECTOR } from 'sql/parts/dashboard/dashboard.component';
|
||||
import { ConnectionContextkey } from 'sql/parts/connection/common/connectionContextKey';
|
||||
import { ConnectionContextKey } from 'sql/parts/connection/common/connectionContextKey';
|
||||
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
||||
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
@@ -71,6 +71,7 @@ export class DashboardEditor extends BaseEditor {
|
||||
* To be called when the container of this editor changes size.
|
||||
*/
|
||||
public layout(dimension: DOM.Dimension): void {
|
||||
this._dashboardService.layout(dimension);
|
||||
}
|
||||
|
||||
public setInput(input: DashboardInput, options: EditorOptions): TPromise<void> {
|
||||
@@ -110,7 +111,7 @@ export class DashboardEditor extends BaseEditor {
|
||||
let serverInfo = this._connMan.getConnectionInfo(this.input.uri).serverInfo;
|
||||
this._dashboardService.changeToDashboard({ profile, serverInfo });
|
||||
let scopedContextService = this._contextKeyService.createScoped(input.container);
|
||||
let connectionContextKey = new ConnectionContextkey(scopedContextService);
|
||||
let connectionContextKey = new ConnectionContextKey(scopedContextService);
|
||||
connectionContextKey.set(input.connectionProfile);
|
||||
|
||||
let params: IDashboardComponentParams = {
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
|
||||
import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo';
|
||||
import * as Constants from 'sql/parts/connection/common/constants';
|
||||
import { OEAction } from 'sql/parts/objectExplorer/viewlet/objectExplorerActions';
|
||||
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
||||
import { IScriptingService } from 'sql/services/scripting/scriptingService';
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import { error } from 'sql/base/common/log';
|
||||
import { clone, mixin } from 'sql/base/common/objects';
|
||||
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
||||
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { escape } from 'sql/base/common/strings';
|
||||
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
@@ -367,11 +368,12 @@ export class EditDataComponent extends GridParentComponent implements OnInit, On
|
||||
columnDefinitions: resultSet.columnInfo.map((c, i) => {
|
||||
let isLinked = c.isXml || c.isJson;
|
||||
let linkType = c.isXml ? 'xml' : 'json';
|
||||
|
||||
return {
|
||||
id: i.toString(),
|
||||
name: c.columnName === 'Microsoft SQL Server 2005 XML Showplan'
|
||||
? 'XML Showplan'
|
||||
: c.columnName,
|
||||
: escape(c.columnName),
|
||||
type: self.stringToFieldType('string'),
|
||||
formatter: isLinked ? Services.hyperLinkFormatter : Services.textFormatter,
|
||||
asyncPostRender: isLinked ? self.linkHandler(linkType) : undefined,
|
||||
|
||||
@@ -348,11 +348,12 @@ export class QueryComponent extends GridParentComponent implements OnInit, OnDes
|
||||
columnDefinitions: resultSet.columnInfo.map((c, i) => {
|
||||
let isLinked = c.isXml || c.isJson;
|
||||
let linkType = c.isXml ? 'xml' : 'json';
|
||||
|
||||
return {
|
||||
id: i.toString(),
|
||||
name: c.columnName === 'Microsoft SQL Server 2005 XML Showplan'
|
||||
? 'XML Showplan'
|
||||
: c.columnName,
|
||||
: escape(c.columnName),
|
||||
type: self.stringToFieldType('string'),
|
||||
formatter: isLinked ? Services.hyperLinkFormatter : Services.textFormatter,
|
||||
asyncPostRender: isLinked ? self.linkHandler(linkType) : undefined
|
||||
|
||||
@@ -7,18 +7,11 @@ import 'vs/css!../common/media/jobs';
|
||||
import 'sql/parts/dashboard/common/dashboardPanelStyles';
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, Injectable } from '@angular/core';
|
||||
import * as Utils from 'sql/parts/connection/common/utils';
|
||||
import { RefreshWidgetAction, EditDashboardAction } from 'sql/parts/dashboard/common/actions';
|
||||
import { IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as themeColors from 'vs/workbench/common/theme';
|
||||
import { DashboardPage } from 'sql/parts/dashboard/common/dashboardPage.component';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||
import { AgentJobInfo, AgentJobHistoryInfo } from 'sqlops';
|
||||
import { Component, Inject, forwardRef, ChangeDetectorRef, ViewChild, Injectable } from '@angular/core';
|
||||
import { AgentJobInfo } from 'sqlops';
|
||||
import { PanelComponent, IPanelOptions, NavigationBarLayout } from 'sql/base/browser/ui/panel/panel.component';
|
||||
import { IJobManagementService } from 'sql/parts/jobManagement/common/interfaces';
|
||||
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
||||
|
||||
|
||||
export const DASHBOARD_SELECTOR: string = 'agentview-component';
|
||||
@@ -32,12 +25,6 @@ export class AgentViewComponent {
|
||||
|
||||
@ViewChild(PanelComponent) private _panel: PanelComponent;
|
||||
|
||||
// tslint:disable:no-unused-variable
|
||||
private readonly jobsComponentTitle: string = nls.localize('jobview.Jobs', "Jobs");
|
||||
private readonly alertsComponentTitle: string = nls.localize('jobview.Alerts', "Alerts");
|
||||
private readonly proxiesComponentTitle: string = nls.localize('jobview.Proxies', "Proxies");
|
||||
private readonly operatorsComponentTitle: string = nls.localize('jobview.Operators', "Operators");
|
||||
|
||||
private _showHistory: boolean = false;
|
||||
private _jobId: string = null;
|
||||
private _agentJobInfo: AgentJobInfo = null;
|
||||
@@ -49,6 +36,11 @@ export class AgentViewComponent {
|
||||
public proxiesIconClass: string = 'proxiesview-icon';
|
||||
public operatorsIconClass: string = 'operatorsview-icon';
|
||||
|
||||
private readonly jobsComponentTitle: string = nls.localize('jobview.Jobs', "Jobs");
|
||||
private readonly alertsComponentTitle: string = nls.localize('jobview.Alerts', "Alerts");
|
||||
private readonly proxiesComponentTitle: string = nls.localize('jobview.Proxies', "Proxies");
|
||||
private readonly operatorsComponentTitle: string = nls.localize('jobview.Operators', "Operators");
|
||||
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private readonly panelOpt: IPanelOptions = {
|
||||
showTabsWhenOne: true,
|
||||
@@ -58,7 +50,8 @@ export class AgentViewComponent {
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef,
|
||||
@Inject(IJobManagementService) jobManagementService: IJobManagementService) {
|
||||
@Inject(IJobManagementService) jobManagementService: IJobManagementService,
|
||||
@Inject(IDashboardService) dashboardService: IDashboardService,) {
|
||||
this._expanded = new Map<string, string>();
|
||||
|
||||
let self = this;
|
||||
|
||||
@@ -34,6 +34,8 @@ export interface IJobManagementService {
|
||||
getProxies(connectionUri: string): Thenable<sqlops.AgentProxiesResult>;
|
||||
deleteProxy(connectionUri: string, proxy: sqlops.AgentProxyInfo): Thenable<sqlops.ResultStatus>;
|
||||
|
||||
getCredentials(connectionUri: string): Thenable<sqlops.GetCredentialsResult>;
|
||||
|
||||
jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus>;
|
||||
addToCache(server: string, cache: JobCacheObject);
|
||||
jobCacheObjectMap: { [server: string]: JobCacheObject; };
|
||||
|
||||
@@ -145,11 +145,17 @@ export class EditJobAction extends Action {
|
||||
public static ID = 'jobaction.editJob';
|
||||
public static LABEL = nls.localize('jobaction.editJob', "Edit Job");
|
||||
|
||||
constructor() {
|
||||
constructor(
|
||||
@ICommandService private _commandService: ICommandService
|
||||
) {
|
||||
super(EditJobAction.ID, EditJobAction.LABEL);
|
||||
}
|
||||
|
||||
public run(actionInfo: IJobActionInfo): TPromise<boolean> {
|
||||
this._commandService.executeCommand(
|
||||
'agent.openJobDialog',
|
||||
actionInfo.ownerUri,
|
||||
actionInfo.targetObject);
|
||||
return TPromise.as(true);
|
||||
}
|
||||
}
|
||||
@@ -324,11 +330,17 @@ export class EditOperatorAction extends Action {
|
||||
public static ID = 'jobaction.editAlert';
|
||||
public static LABEL = nls.localize('jobaction.editOperator', "Edit Operator");
|
||||
|
||||
constructor() {
|
||||
constructor(
|
||||
@ICommandService private _commandService: ICommandService
|
||||
) {
|
||||
super(EditOperatorAction.ID, EditOperatorAction.LABEL);
|
||||
}
|
||||
|
||||
public run(info: any): TPromise<boolean> {
|
||||
public run(actionInfo: IJobActionInfo): TPromise<boolean> {
|
||||
this._commandService.executeCommand(
|
||||
'agent.openOperatorDialog',
|
||||
actionInfo.ownerUri,
|
||||
actionInfo.targetObject);
|
||||
return TPromise.as(true);
|
||||
}
|
||||
}
|
||||
@@ -398,11 +410,17 @@ export class EditProxyAction extends Action {
|
||||
public static ID = 'jobaction.editProxy';
|
||||
public static LABEL = nls.localize('jobaction.editProxy', "Edit Proxy");
|
||||
|
||||
constructor() {
|
||||
constructor(
|
||||
@ICommandService private _commandService: ICommandService
|
||||
) {
|
||||
super(EditProxyAction.ID, EditProxyAction.LABEL);
|
||||
}
|
||||
|
||||
public run(info: any): TPromise<boolean> {
|
||||
public run(actionInfo: IJobActionInfo): TPromise<boolean> {
|
||||
this._commandService.executeCommand(
|
||||
'agent.openProxyDialog',
|
||||
actionInfo.ownerUri,
|
||||
actionInfo.targetObject);
|
||||
return TPromise.as(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,12 @@ export class JobManagementService implements IJobManagementService {
|
||||
});
|
||||
}
|
||||
|
||||
public getCredentials(connectionUri: string): Thenable<sqlops.GetCredentialsResult> {
|
||||
return this._runAction(connectionUri, (runner) => {
|
||||
return runner.getCredentials(connectionUri);
|
||||
});
|
||||
}
|
||||
|
||||
public getJobHistory(connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> {
|
||||
return this._runAction(connectionUri, (runner) => {
|
||||
return runner.getJobHistory(connectionUri, jobID);
|
||||
|
||||
@@ -32,23 +32,11 @@ jobhistory-component {
|
||||
}
|
||||
|
||||
.jobview-grid {
|
||||
height: 94.7%;
|
||||
height: calc(100% - 75px);
|
||||
width : 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vs-dark #jobsDiv .slick-header-column {
|
||||
background: #333333 !important;
|
||||
}
|
||||
|
||||
#jobsDiv .slick-header-column {
|
||||
background-color: transparent !important;
|
||||
background: white !important;
|
||||
border: 0px !important;
|
||||
font-weight: bold;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.vs-dark #agentViewDiv .slick-header-column {
|
||||
background: #333333 !important;
|
||||
}
|
||||
@@ -58,7 +46,6 @@ jobhistory-component {
|
||||
background: white !important;
|
||||
border: 0px !important;
|
||||
font-weight: bold;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.vs-dark #jobsDiv jobsview-component .jobview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
@@ -164,7 +151,7 @@ jobhistory-component {
|
||||
}
|
||||
|
||||
#jobsDiv .preload {
|
||||
font-size: 18px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#jobsDiv .dynamic-cell-detail > :first-child {
|
||||
@@ -299,19 +286,20 @@ table.jobprevruns > tbody {
|
||||
|
||||
|
||||
#alertsDiv .jobalertsview-grid {
|
||||
height: 94.7%;
|
||||
height: calc(100% - 75px);
|
||||
width : 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#operatorsDiv .joboperatorsview-grid {
|
||||
height: 94.7%;
|
||||
height: calc(100% - 75px);
|
||||
width : 100%;
|
||||
display: block;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#proxiesDiv .jobproxiesview-grid {
|
||||
height: 94.7%;
|
||||
height: calc(100% - 75px);
|
||||
width : 100%;
|
||||
display: block;
|
||||
}
|
||||
@@ -339,4 +327,97 @@ jobsview-component .actionbar-container {
|
||||
|
||||
jobsview-component .jobview-grid .slick-cell.error-row {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.vs-dark #alertsDiv jobalertsview-component .jobalertsview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
background:#333333;
|
||||
}
|
||||
|
||||
#alertsDiv jobalertsview-component .jobalertsview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
background: white;
|
||||
border-right: transparent !important;
|
||||
border-left: transparent !important;
|
||||
line-height: 33px !important;
|
||||
}
|
||||
|
||||
#alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
#alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
#alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row> .slick-cell.hovered {
|
||||
background: #dcdcdc !important;
|
||||
}
|
||||
|
||||
.vs-dark #alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.vs-dark #alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.vs-dark #alertsDiv .jobalertsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell {
|
||||
background: #444444 !important;
|
||||
}
|
||||
|
||||
.vs-dark .jobalertsview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
border-left: 1px dotted white;
|
||||
}
|
||||
|
||||
.jobalertsview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
border-left: 1px dotted #444444;
|
||||
}
|
||||
|
||||
.vs-dark #operatorsDiv joboperatorsview-component .joboperatorsview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
background:#333333;
|
||||
}
|
||||
|
||||
#operatorsDiv joboperatorsview-component .joboperatorsview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
background: white;
|
||||
border-right: transparent !important;
|
||||
border-left: transparent !important;
|
||||
line-height: 33px !important;
|
||||
}
|
||||
|
||||
#operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
#operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
#operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row> .slick-cell.hovered {
|
||||
background: #dcdcdc !important;
|
||||
}
|
||||
|
||||
.vs-dark #operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.vs-dark #operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.vs-dark #operatorsDiv .joboperatorsview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell {
|
||||
background: #444444 !important;
|
||||
}
|
||||
|
||||
.vs-dark .joboperatorsview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
border-left: 1px dotted white;
|
||||
}
|
||||
|
||||
.joboperatorsview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
border-left: 1px dotted #444444;
|
||||
}
|
||||
|
||||
.vs-dark #proxiesDiv jobproxiesview-component .jobproxiesview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
background:#333333;
|
||||
}
|
||||
|
||||
#proxiesDiv jobproxiesview-component .jobproxiesview-grid .grid-canvas .ui-widget-content.slick-row .slick-cell {
|
||||
background: white;
|
||||
border-right: transparent !important;
|
||||
border-left: transparent !important;
|
||||
line-height: 33px !important;
|
||||
}
|
||||
|
||||
#proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
#proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell,
|
||||
#proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row> .slick-cell.hovered {
|
||||
background: #dcdcdc !important;
|
||||
}
|
||||
|
||||
.vs-dark #proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row:hover > .slick-cell,
|
||||
.vs-dark #proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row > .slick-cell.hovered,
|
||||
.vs-dark #proxiesDiv .jobproxiesview-grid > .monaco-table .slick-viewport > .grid-canvas > .ui-widget-content.slick-row.hovered > .slick-cell {
|
||||
background: #444444 !important;
|
||||
}
|
||||
|
||||
.vs-dark .jobproxiesview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
border-left: 1px dotted white;
|
||||
}
|
||||
|
||||
.jobproxiesview-grid > .monaco-table .slick-header-columns .slick-resizable-handle {
|
||||
border-left: 1px dotted #444444;
|
||||
}
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
|
||||
<div #actionbarContainer class="actionbar-container"></div>
|
||||
|
||||
<div #jobalertsgrid class="jobview-grid"></div>
|
||||
<div #jobalertsgrid class="jobalertsview-grid"></div>
|
||||
|
||||
@@ -29,9 +29,10 @@ import { IAction } from 'vs/base/common/actions';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
||||
|
||||
export const VIEW_SELECTOR: string = 'jobalertsview-component';
|
||||
export const ROW_HEIGHT: number = 45;
|
||||
export const ROW_HEIGHT: number = 30;
|
||||
|
||||
@Component({
|
||||
selector: VIEW_SELECTOR,
|
||||
@@ -73,8 +74,9 @@ export class AlertsViewComponent extends JobManagementView implements OnInit {
|
||||
@Inject(IInstantiationService) instantiationService: IInstantiationService,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) commonService: CommonServiceInterface,
|
||||
@Inject(IContextMenuService) contextMenuService: IContextMenuService,
|
||||
@Inject(IKeybindingService) keybindingService: IKeybindingService) {
|
||||
super(commonService, contextMenuService, keybindingService, instantiationService);
|
||||
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
||||
@Inject(IDashboardService) _dashboardService: IDashboardService) {
|
||||
super(commonService, _dashboardService, contextMenuService, keybindingService, instantiationService);
|
||||
this._isCloud = commonService.connectionManagementService.connectionInfo.serverInfo.isCloud;
|
||||
}
|
||||
|
||||
@@ -85,7 +87,14 @@ export class AlertsViewComponent extends JobManagementView implements OnInit {
|
||||
}
|
||||
|
||||
public layout() {
|
||||
this._table.layout(new dom.Dimension(dom.getContentWidth(this._gridEl.nativeElement), dom.getContentHeight(this._gridEl.nativeElement)));
|
||||
let height = dom.getContentHeight(this._gridEl.nativeElement) - 10;
|
||||
if (height < 0) {
|
||||
height = 0;
|
||||
}
|
||||
|
||||
this._table.layout(new dom.Dimension(
|
||||
dom.getContentWidth(this._gridEl.nativeElement),
|
||||
height));
|
||||
}
|
||||
|
||||
onFirstVisible() {
|
||||
@@ -94,13 +103,6 @@ export class AlertsViewComponent extends JobManagementView implements OnInit {
|
||||
column.rerenderOnResize = true;
|
||||
return column;
|
||||
});
|
||||
let options = <Slick.GridOptions<any>>{
|
||||
syncColumnCellResize: true,
|
||||
enableColumnReorder: false,
|
||||
rowHeight: ROW_HEIGHT,
|
||||
enableCellNavigation: true,
|
||||
forceFitColumns: true
|
||||
};
|
||||
|
||||
this.dataView = new Slick.Data.DataView();
|
||||
|
||||
@@ -164,7 +166,17 @@ export class AlertsViewComponent extends JobManagementView implements OnInit {
|
||||
|
||||
public openCreateAlertDialog() {
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
this._commandService.executeCommand('agent.openAlertDialog', ownerUri);
|
||||
this._jobManagementService.getJobs(ownerUri).then((result) => {
|
||||
if (result && result.jobs.length > 0) {
|
||||
let jobs = [];
|
||||
result.jobs.forEach(job => {
|
||||
jobs.push(job.name);
|
||||
});
|
||||
this._commandService.executeCommand('agent.openAlertDialog', ownerUri, null, jobs);
|
||||
} else {
|
||||
this._commandService.executeCommand('agent.openAlertDialog', ownerUri, null, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private refreshJobs() {
|
||||
|
||||
@@ -154,8 +154,9 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<jobstepsview-component *ngIf="showSteps === true"></jobstepsview-component>
|
||||
<div #jobsteps>
|
||||
<jobstepsview-component *ngIf="showSteps === true"></jobstepsview-component>
|
||||
</div>
|
||||
<h3 *ngIf="showSteps === false">No Steps Available</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'vs/css!./jobHistory';
|
||||
import 'vs/css!sql/media/icons/common-icons';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { OnInit, Component, Inject, Input, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, ChangeDetectionStrategy, Injectable } from '@angular/core';
|
||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||
import { AgentViewComponent } from 'sql/parts/jobManagement/agent/agentView.component';
|
||||
@@ -22,30 +23,33 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work
|
||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { JobManagementView } from 'sql/parts/jobManagement/views/jobManagementView';
|
||||
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
|
||||
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
|
||||
export const DASHBOARD_SELECTOR: string = 'jobhistory-component';
|
||||
|
||||
@Component({
|
||||
selector: DASHBOARD_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./jobHistory.component.html')),
|
||||
providers: [{ provide: TabChild, useExisting: forwardRef(() => JobHistoryComponent) }],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
@Injectable()
|
||||
export class JobHistoryComponent extends Disposable implements OnInit {
|
||||
export class JobHistoryComponent extends JobManagementView implements OnInit {
|
||||
|
||||
private _tree: Tree;
|
||||
private _treeController: JobHistoryController;
|
||||
private _treeDataSource: JobHistoryDataSource;
|
||||
private _treeRenderer: JobHistoryRenderer;
|
||||
private _treeFilter: JobHistoryFilter;
|
||||
private _actionBar: Taskbar;
|
||||
|
||||
@ViewChild('table') private _tableContainer: ElementRef;
|
||||
@ViewChild('actionbarContainer') private _actionbarContainer: ElementRef;
|
||||
@ViewChild('jobsteps') private _jobStepsView: ElementRef;
|
||||
|
||||
@Input() public agentJobInfo: sqlops.AgentJobInfo = undefined;
|
||||
@Input() public agentJobHistories: sqlops.AgentJobHistoryInfo[] = undefined;
|
||||
@@ -67,21 +71,23 @@ export class JobHistoryComponent extends Disposable implements OnInit {
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _dashboardService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) commonService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => AgentViewComponent)) private _agentViewComponent: AgentViewComponent,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||
@Inject(INotificationService) private _notificationService: INotificationService,
|
||||
@Inject(IInstantiationService) private instantiationService: IInstantiationService,
|
||||
@Inject(IContextMenuService) private contextMenuService: IContextMenuService,
|
||||
@Inject(IJobManagementService) private _jobManagementService: IJobManagementService
|
||||
@Inject(IJobManagementService) private _jobManagementService: IJobManagementService,
|
||||
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
||||
@Inject(IDashboardService) dashboardService: IDashboardService
|
||||
) {
|
||||
super();
|
||||
super(commonService, dashboardService, contextMenuService, keybindingService, instantiationService);
|
||||
this._treeController = new JobHistoryController();
|
||||
this._treeDataSource = new JobHistoryDataSource();
|
||||
this._treeRenderer = new JobHistoryRenderer();
|
||||
this._treeFilter = new JobHistoryFilter();
|
||||
let jobCacheObjectMap = this._jobManagementService.jobCacheObjectMap;
|
||||
this._serverName = _dashboardService.connectionManagementService.connectionInfo.connectionProfile.serverName;
|
||||
this._serverName = commonService.connectionManagementService.connectionInfo.connectionProfile.serverName;
|
||||
let jobCache = jobCacheObjectMap[this._serverName];
|
||||
if (jobCache) {
|
||||
this._jobCacheObject = jobCache;
|
||||
@@ -93,7 +99,11 @@ export class JobHistoryComponent extends Disposable implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
|
||||
// set base class elements
|
||||
this._visibilityElement = this._tableContainer;
|
||||
this._parentComponent = this._agentViewComponent;
|
||||
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
const self = this;
|
||||
this._treeController.onClick = (tree, element, event, origin = 'mouse') => {
|
||||
const payload = { origin: origin };
|
||||
@@ -130,56 +140,13 @@ export class JobHistoryComponent extends Disposable implements OnInit {
|
||||
}, {verticalScrollMode: ScrollbarVisibility.Visible});
|
||||
this._register(attachListStyler(this._tree, this.themeService));
|
||||
this._tree.layout(JobHistoryComponent.INITIAL_TREE_HEIGHT);
|
||||
this._initActionBar();
|
||||
$(window).resize(() => {
|
||||
let historyDetails = $('.overview-container').get(0);
|
||||
let statusBar = $('.part.statusbar').get(0);
|
||||
if (historyDetails && statusBar) {
|
||||
let historyBottom = historyDetails.getBoundingClientRect().bottom;
|
||||
let statusTop = statusBar.getBoundingClientRect().top;
|
||||
this._tree.layout(statusTop - historyBottom - JobHistoryComponent.HEADING_HEIGHT);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.initActionBar();
|
||||
|
||||
ngAfterContentChecked() {
|
||||
this._agentJobInfo = this._agentViewComponent.agentJobInfo;
|
||||
if (!this.agentJobInfo) {
|
||||
this.agentJobInfo = this._agentJobInfo;
|
||||
this.setActions();
|
||||
}
|
||||
if (this._isVisible === false && this._tableContainer.nativeElement.offsetParent !== null) {
|
||||
this._isVisible = true;
|
||||
let jobHistories = this._jobCacheObject.jobHistories[this._agentViewComponent.jobId];
|
||||
if (jobHistories && jobHistories.length > 0) {
|
||||
const self = this;
|
||||
if (this._jobCacheObject.prevJobID === this._agentViewComponent.jobId || jobHistories[0].jobId === this._agentViewComponent.jobId) {
|
||||
this._showPreviousRuns = true;
|
||||
this.buildHistoryTree(self, jobHistories);
|
||||
$('jobhistory-component .history-details .prev-run-list .monaco-tree').attr('tabIndex', '-1');
|
||||
$('jobhistory-component .history-details .prev-run-list .monaco-tree-row').attr('tabIndex', '0');
|
||||
this._cd.detectChanges();
|
||||
}
|
||||
} else if (jobHistories && jobHistories.length === 0 ){
|
||||
this._showPreviousRuns = false;
|
||||
this._showSteps = false;
|
||||
this._noJobsAvailable = true;
|
||||
this._cd.detectChanges();
|
||||
} else {
|
||||
this.loadHistory();
|
||||
}
|
||||
this._jobCacheObject.prevJobID = this._agentViewComponent.jobId;
|
||||
} else if (this._isVisible === true && this._agentViewComponent.refresh) {
|
||||
this.loadHistory();
|
||||
this._agentViewComponent.refresh = false;
|
||||
} else if (this._isVisible === true && this._tableContainer.nativeElement.offsetParent === null) {
|
||||
this._isVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private loadHistory() {
|
||||
const self = this;
|
||||
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
this._jobManagementService.getJobHistory(ownerUri, this._agentViewComponent.jobId).then((result) => {
|
||||
if (result && result.jobs) {
|
||||
if (result.jobs.length > 0) {
|
||||
@@ -273,12 +240,71 @@ export class JobHistoryComponent extends Disposable implements OnInit {
|
||||
JobManagementUtilities.getActionIconClassName(startIcon, stopIcon, this.agentJobInfo.currentExecutionStatus);
|
||||
}
|
||||
|
||||
public onFirstVisible() {
|
||||
this._agentJobInfo = this._agentViewComponent.agentJobInfo;
|
||||
if (!this.agentJobInfo) {
|
||||
this.agentJobInfo = this._agentJobInfo;
|
||||
this.setActions();
|
||||
}
|
||||
|
||||
private _initActionBar() {
|
||||
if (this.isRefreshing ) {
|
||||
this.loadHistory();
|
||||
return;
|
||||
}
|
||||
|
||||
let jobHistories = this._jobCacheObject.jobHistories[this._agentViewComponent.jobId];
|
||||
if (jobHistories && jobHistories.length > 0) {
|
||||
const self = this;
|
||||
if (this._jobCacheObject.prevJobID === this._agentViewComponent.jobId || jobHistories[0].jobId === this._agentViewComponent.jobId) {
|
||||
this._showPreviousRuns = true;
|
||||
this.buildHistoryTree(self, jobHistories);
|
||||
$('jobhistory-component .history-details .prev-run-list .monaco-tree').attr('tabIndex', '-1');
|
||||
$('jobhistory-component .history-details .prev-run-list .monaco-tree-row').attr('tabIndex', '0');
|
||||
this._cd.detectChanges();
|
||||
}
|
||||
} else if (jobHistories && jobHistories.length === 0 ){
|
||||
this._showPreviousRuns = false;
|
||||
this._showSteps = false;
|
||||
this._noJobsAvailable = true;
|
||||
this._cd.detectChanges();
|
||||
} else {
|
||||
this.loadHistory();
|
||||
}
|
||||
this._jobCacheObject.prevJobID = this._agentViewComponent.jobId;
|
||||
}
|
||||
|
||||
public layout() {
|
||||
let historyDetails = $('.overview-container').get(0);
|
||||
let statusBar = $('.part.statusbar').get(0);
|
||||
if (historyDetails && statusBar) {
|
||||
let historyBottom = historyDetails.getBoundingClientRect().bottom;
|
||||
let statusTop = statusBar.getBoundingClientRect().top;
|
||||
let height: number = statusTop - historyBottom - JobHistoryComponent.HEADING_HEIGHT;
|
||||
|
||||
if (this._table) {
|
||||
this._table.layout(new dom.Dimension(
|
||||
dom.getContentWidth(this._tableContainer.nativeElement),
|
||||
height));
|
||||
}
|
||||
|
||||
if (this._tree) {
|
||||
this._tree.layout(height);
|
||||
}
|
||||
|
||||
if (this._jobStepsView) {
|
||||
let element = this._jobStepsView.nativeElement as HTMLElement;
|
||||
if (element) {
|
||||
element.style.height = height + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected initActionBar() {
|
||||
let runJobAction = this.instantiationService.createInstance(RunJobAction);
|
||||
let stopJobAction = this.instantiationService.createInstance(StopJobAction);
|
||||
let newStepAction = this.instantiationService.createInstance(NewStepAction);
|
||||
let taskbar = <HTMLElement>this._actionbarContainer.nativeElement;
|
||||
let taskbar = <HTMLElement>this.actionBarContainer.nativeElement;
|
||||
this._actionBar = new Taskbar(taskbar, this.contextMenuService);
|
||||
this._actionBar.context = this;
|
||||
this._actionBar.setContent([
|
||||
@@ -299,7 +325,7 @@ export class JobHistoryComponent extends Disposable implements OnInit {
|
||||
}
|
||||
|
||||
public get ownerUri(): string {
|
||||
return this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
|
||||
return this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
}
|
||||
|
||||
public get serverName(): string {
|
||||
|
||||
@@ -167,7 +167,7 @@ table.step-list tr.step-row td {
|
||||
}
|
||||
|
||||
.vs-dark .history-details > .job-steps {
|
||||
display: inline-block;
|
||||
display: block;
|
||||
border-left: 3px solid #444444;
|
||||
padding-left: 10px;
|
||||
height: 100%;
|
||||
@@ -176,10 +176,12 @@ table.step-list tr.step-row td {
|
||||
}
|
||||
|
||||
.history-details > .job-steps {
|
||||
display: inline-block;
|
||||
display: block;
|
||||
border-left: 3px solid #f4f4f4;
|
||||
padding-left: 10px;
|
||||
height: 100%;
|
||||
width: 90%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.history-details > .job-steps > .step-list {
|
||||
|
||||
@@ -16,8 +16,10 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Taskbar } from '../../../base/browser/ui/taskbar/taskbar';
|
||||
import { JobsRefreshAction } from 'sql/parts/jobManagement/common/jobActions';
|
||||
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
|
||||
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
||||
|
||||
export abstract class JobManagementView extends Disposable implements AfterContentChecked {
|
||||
export abstract class JobManagementView extends TabChild implements AfterContentChecked {
|
||||
protected isVisible: boolean = false;
|
||||
protected isInitialized: boolean = false;
|
||||
protected isRefreshing: boolean = false;
|
||||
@@ -32,10 +34,16 @@ export abstract class JobManagementView extends Disposable implements AfterConte
|
||||
|
||||
constructor(
|
||||
protected _commonService: CommonServiceInterface,
|
||||
protected _dashboardService: IDashboardService,
|
||||
protected _contextMenuService: IContextMenuService,
|
||||
protected _keybindingService: IKeybindingService,
|
||||
protected _instantiationService: IInstantiationService) {
|
||||
super();
|
||||
|
||||
let self = this;
|
||||
this._dashboardService.onLayout((d) => {
|
||||
self.layout();
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterContentChecked() {
|
||||
@@ -49,8 +57,9 @@ export abstract class JobManagementView extends Disposable implements AfterConte
|
||||
}
|
||||
} else if (this.isVisible === true && this._parentComponent.refresh === true) {
|
||||
this._showProgressWheel = true;
|
||||
this.onFirstVisible();
|
||||
this.isRefreshing = true;
|
||||
this.onFirstVisible();
|
||||
this.layout();
|
||||
this._parentComponent.refresh = false;
|
||||
} else if (this.isVisible === true && this._visibilityElement.nativeElement.offsetParent === null) {
|
||||
this.isVisible = false;
|
||||
|
||||
@@ -8,21 +8,28 @@ import 'vs/css!./jobStepsView';
|
||||
import { OnInit, Component, Inject, forwardRef, ElementRef, ChangeDetectorRef, ViewChild, Injectable, AfterContentChecked } from '@angular/core';
|
||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { JobStepsViewController, JobStepsViewDataSource, JobStepsViewFilter,
|
||||
JobStepsViewRenderer, JobStepsViewModel} from 'sql/parts/jobManagement/views/jobStepsViewTree';
|
||||
import { JobHistoryComponent } from 'sql/parts/jobManagement/views/jobHistory.component';
|
||||
import { JobManagementView } from 'sql/parts/jobManagement/views/jobManagementView';
|
||||
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { TabChild } from 'sql/base/browser/ui/panel/tab.component';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
|
||||
export const JOBSTEPSVIEW_SELECTOR: string = 'jobstepsview-component';
|
||||
|
||||
@Component({
|
||||
selector: JOBSTEPSVIEW_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./jobStepsView.component.html'))
|
||||
templateUrl: decodeURI(require.toUrl('./jobStepsView.component.html')),
|
||||
providers: [{ provide: TabChild, useExisting: forwardRef(() => JobStepsViewComponent) }],
|
||||
})
|
||||
export class JobStepsViewComponent extends Disposable implements OnInit, AfterContentChecked {
|
||||
export class JobStepsViewComponent extends JobManagementView implements OnInit, AfterContentChecked {
|
||||
|
||||
private _tree: Tree;
|
||||
private _treeController = new JobStepsViewController();
|
||||
@@ -33,15 +40,18 @@ export class JobStepsViewComponent extends Disposable implements OnInit, AfterCo
|
||||
|
||||
@ViewChild('table') private _tableContainer: ElementRef;
|
||||
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ElementRef)) el: ElementRef,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _cd: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _dashboardService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) commonService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => JobHistoryComponent)) private _jobHistoryComponent: JobHistoryComponent,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||
@Inject(IInstantiationService) instantiationService: IInstantiationService,
|
||||
@Inject(IContextMenuService) contextMenuService: IContextMenuService,
|
||||
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
||||
@Inject(IDashboardService) dashboardService: IDashboardService
|
||||
) {
|
||||
super();
|
||||
super(commonService, dashboardService, contextMenuService, keybindingService, instantiationService);
|
||||
}
|
||||
|
||||
ngAfterContentChecked() {
|
||||
@@ -64,7 +74,7 @@ export class JobStepsViewComponent extends Disposable implements OnInit, AfterCo
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
this._tree = new Tree(this._tableContainer.nativeElement, {
|
||||
controller: this._treeController,
|
||||
dataSource: this._treeDataSource,
|
||||
@@ -73,5 +83,20 @@ export class JobStepsViewComponent extends Disposable implements OnInit, AfterCo
|
||||
}, {verticalScrollMode: ScrollbarVisibility.Visible});
|
||||
this._register(attachListStyler(this._tree, this.themeService));
|
||||
}
|
||||
|
||||
public onFirstVisible() {
|
||||
}
|
||||
|
||||
public layout() {
|
||||
let jobsViewToolbar = $('jobhistory-component .actionbar-container').get(0);
|
||||
let statusBar = $('.part.statusbar').get(0);
|
||||
if (jobsViewToolbar && statusBar) {
|
||||
let toolbarBottom = jobsViewToolbar.getBoundingClientRect().bottom;
|
||||
let statusTop = statusBar.getBoundingClientRect().top;
|
||||
this._table.layout(new dom.Dimension(
|
||||
dom.getContentWidth(this._tableContainer.nativeElement),
|
||||
statusTop - toolbarBottom));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
||||
|
||||
export const JOBSVIEW_SELECTOR: string = 'jobsview-component';
|
||||
export const ROW_HEIGHT: number = 45;
|
||||
@@ -99,8 +100,9 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
@Inject(IInstantiationService) instantiationService: IInstantiationService,
|
||||
@Inject(IContextMenuService) contextMenuService: IContextMenuService,
|
||||
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
||||
@Inject(IDashboardService) _dashboardService: IDashboardService
|
||||
) {
|
||||
super(commonService, contextMenuService, keybindingService, instantiationService);
|
||||
super(commonService, _dashboardService, contextMenuService, keybindingService, instantiationService);
|
||||
let jobCacheObjectMap = this._jobManagementService.jobCacheObjectMap;
|
||||
this._serverName = commonService.connectionManagementService.connectionInfo.connectionProfile.serverName;
|
||||
let jobCache = jobCacheObjectMap[this._serverName];
|
||||
@@ -121,7 +123,15 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
}
|
||||
|
||||
public layout() {
|
||||
this._table.layout(new dom.Dimension(dom.getContentWidth(this._gridEl.nativeElement), dom.getContentHeight(this._gridEl.nativeElement)));
|
||||
let jobsViewToolbar = $('jobsview-component .actionbar-container').get(0);
|
||||
let statusBar = $('.part.statusbar').get(0);
|
||||
if (jobsViewToolbar && statusBar) {
|
||||
let toolbarBottom = jobsViewToolbar.getBoundingClientRect().bottom;
|
||||
let statusTop = statusBar.getBoundingClientRect().top;
|
||||
this._table.layout(new dom.Dimension(
|
||||
dom.getContentWidth(this._gridEl.nativeElement),
|
||||
statusTop - toolbarBottom));
|
||||
}
|
||||
}
|
||||
|
||||
onFirstVisible() {
|
||||
@@ -141,7 +151,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
enableColumnReorder: false,
|
||||
rowHeight: ROW_HEIGHT,
|
||||
enableCellNavigation: true,
|
||||
forceFitColumns: true
|
||||
forceFitColumns: false
|
||||
};
|
||||
|
||||
this.dataView = new Slick.Data.DataView({ inlineFilters: false });
|
||||
@@ -328,7 +338,6 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
this.dataView.beginUpdate();
|
||||
this.dataView.setItems(jobViews);
|
||||
this.dataView.setFilter((item) => this.filter(item));
|
||||
|
||||
this.dataView.endUpdate();
|
||||
this._table.autosizeColumns();
|
||||
this._table.resizeCanvas();
|
||||
@@ -341,17 +350,6 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
});
|
||||
|
||||
const self = this;
|
||||
$(window).resize(() => {
|
||||
let jobsViewToolbar = $('jobsview-component .actionbar-container').get(0);
|
||||
let statusBar = $('.part.statusbar').get(0);
|
||||
if (jobsViewToolbar && statusBar) {
|
||||
let toolbarBottom = jobsViewToolbar.getBoundingClientRect().bottom;
|
||||
let statusTop = statusBar.getBoundingClientRect().top;
|
||||
$('agentview-component #jobsDiv .jobview-grid').css('height', statusTop - toolbarBottom);
|
||||
self._table.resizeCanvas();
|
||||
}
|
||||
});
|
||||
|
||||
this._table.grid.onColumnsResized.subscribe((e, data: any) => {
|
||||
let nameWidth: number = data.grid.getColumnWidths()[1];
|
||||
// adjust job name when resized
|
||||
@@ -844,7 +842,7 @@ export class JobsViewComponent extends JobManagementView implements OnInit {
|
||||
|
||||
public openCreateJobDialog() {
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
this._commandService.executeCommand('agent.openCreateJobDialog', ownerUri);
|
||||
this._commandService.executeCommand('agent.openJobDialog', ownerUri);
|
||||
}
|
||||
|
||||
public refreshJobs() {
|
||||
|
||||
@@ -29,9 +29,10 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
||||
|
||||
export const VIEW_SELECTOR: string = 'joboperatorsview-component';
|
||||
export const ROW_HEIGHT: number = 45;
|
||||
export const ROW_HEIGHT: number = 30;
|
||||
|
||||
@Component({
|
||||
selector: VIEW_SELECTOR,
|
||||
@@ -73,9 +74,10 @@ export class OperatorsViewComponent extends JobManagementView implements OnInit
|
||||
@Inject(IInstantiationService) instantiationService: IInstantiationService,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) commonService: CommonServiceInterface,
|
||||
@Inject(IContextMenuService) contextMenuService: IContextMenuService,
|
||||
@Inject(IKeybindingService) keybindingService: IKeybindingService
|
||||
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
||||
@Inject(IDashboardService) _dashboardService: IDashboardService
|
||||
) {
|
||||
super(commonService, contextMenuService, keybindingService, instantiationService);
|
||||
super(commonService, _dashboardService, contextMenuService, keybindingService, instantiationService);
|
||||
this._isCloud = commonService.connectionManagementService.connectionInfo.serverInfo.isCloud;
|
||||
}
|
||||
|
||||
@@ -86,7 +88,14 @@ export class OperatorsViewComponent extends JobManagementView implements OnInit
|
||||
}
|
||||
|
||||
public layout() {
|
||||
this._table.layout(new dom.Dimension(dom.getContentWidth(this._gridEl.nativeElement), dom.getContentHeight(this._gridEl.nativeElement)));
|
||||
let height = dom.getContentHeight(this._gridEl.nativeElement) - 10;
|
||||
if (height < 0) {
|
||||
height = 0;
|
||||
}
|
||||
|
||||
this._table.layout(new dom.Dimension(
|
||||
dom.getContentWidth(this._gridEl.nativeElement),
|
||||
height));
|
||||
}
|
||||
|
||||
onFirstVisible() {
|
||||
@@ -95,13 +104,6 @@ export class OperatorsViewComponent extends JobManagementView implements OnInit
|
||||
column.rerenderOnResize = true;
|
||||
return column;
|
||||
});
|
||||
let options = <Slick.GridOptions<any>>{
|
||||
syncColumnCellResize: true,
|
||||
enableColumnReorder: false,
|
||||
rowHeight: ROW_HEIGHT,
|
||||
enableCellNavigation: true,
|
||||
forceFitColumns: true
|
||||
};
|
||||
|
||||
this.dataView = new Slick.Data.DataView();
|
||||
|
||||
@@ -163,7 +165,7 @@ export class OperatorsViewComponent extends JobManagementView implements OnInit
|
||||
|
||||
public openCreateOperatorDialog() {
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
this._commandService.executeCommand('agent.openCreateOperatorDialog', ownerUri);
|
||||
this._commandService.executeCommand('agent.openOperatorDialog', ownerUri);
|
||||
}
|
||||
|
||||
private refreshJobs() {
|
||||
|
||||
@@ -29,9 +29,10 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDashboardService } from 'sql/services/dashboard/common/dashboardService';
|
||||
|
||||
export const VIEW_SELECTOR: string = 'jobproxiesview-component';
|
||||
export const ROW_HEIGHT: number = 45;
|
||||
export const ROW_HEIGHT: number = 30;
|
||||
|
||||
@Component({
|
||||
selector: VIEW_SELECTOR,
|
||||
@@ -75,9 +76,10 @@ export class ProxiesViewComponent extends JobManagementView implements OnInit {
|
||||
@Inject(IInstantiationService) instantiationService: IInstantiationService,
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) commonService: CommonServiceInterface,
|
||||
@Inject(IContextMenuService) contextMenuService: IContextMenuService,
|
||||
@Inject(IKeybindingService) keybindingService: IKeybindingService
|
||||
@Inject(IKeybindingService) keybindingService: IKeybindingService,
|
||||
@Inject(IDashboardService) _dashboardService: IDashboardService
|
||||
) {
|
||||
super(commonService, contextMenuService, keybindingService, instantiationService);
|
||||
super(commonService, _dashboardService, contextMenuService, keybindingService, instantiationService);
|
||||
this._isCloud = commonService.connectionManagementService.connectionInfo.serverInfo.isCloud;
|
||||
}
|
||||
|
||||
@@ -88,7 +90,14 @@ export class ProxiesViewComponent extends JobManagementView implements OnInit {
|
||||
}
|
||||
|
||||
public layout() {
|
||||
this._table.layout(new dom.Dimension(dom.getContentWidth(this._gridEl.nativeElement), dom.getContentHeight(this._gridEl.nativeElement)));
|
||||
let height = dom.getContentHeight(this._gridEl.nativeElement) - 10;
|
||||
if (height < 0) {
|
||||
height = 0;
|
||||
}
|
||||
|
||||
this._table.layout(new dom.Dimension(
|
||||
dom.getContentWidth(this._gridEl.nativeElement),
|
||||
height));
|
||||
}
|
||||
|
||||
onFirstVisible() {
|
||||
@@ -97,13 +106,6 @@ export class ProxiesViewComponent extends JobManagementView implements OnInit {
|
||||
column.rerenderOnResize = true;
|
||||
return column;
|
||||
});
|
||||
let options = <Slick.GridOptions<any>>{
|
||||
syncColumnCellResize: true,
|
||||
enableColumnReorder: false,
|
||||
rowHeight: ROW_HEIGHT,
|
||||
enableCellNavigation: true,
|
||||
forceFitColumns: true
|
||||
};
|
||||
|
||||
this.dataView = new Slick.Data.DataView();
|
||||
|
||||
@@ -164,7 +166,11 @@ export class ProxiesViewComponent extends JobManagementView implements OnInit {
|
||||
|
||||
public openCreateProxyDialog() {
|
||||
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
|
||||
this._commandService.executeCommand('agent.openCreateProxyDialog', ownerUri);
|
||||
this._jobManagementService.getCredentials(ownerUri).then((result) => {
|
||||
if (result && result.credentials) {
|
||||
this._commandService.executeCommand('agent.openProxyDialog', ownerUri, undefined, result.credentials);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private refreshJobs() {
|
||||
|
||||
@@ -130,11 +130,14 @@ export abstract class ComponentBase extends Disposable implements IComponent, On
|
||||
this.setPropertyFromUI<sqlops.ComponentProperties, number | string>((props, value) => props.width = value, newValue);
|
||||
}
|
||||
|
||||
protected convertSizeToNumber(size: number | string): number {
|
||||
public convertSizeToNumber(size: number | string): number {
|
||||
if (size && typeof (size) === 'string') {
|
||||
if (size.toLowerCase().endsWith('px')) {
|
||||
return +size.replace('px', '');
|
||||
} else if (size.toLowerCase().endsWith('em')) {
|
||||
return +size.replace('em', '') * 11;
|
||||
}
|
||||
} else if (!size) {
|
||||
return 0;
|
||||
}
|
||||
return +size;
|
||||
@@ -148,7 +151,7 @@ export abstract class ComponentBase extends Disposable implements IComponent, On
|
||||
return this.height ? this.convertSize(this.height) : '';
|
||||
}
|
||||
|
||||
protected convertSize(size: number | string, defaultValue?: string): string {
|
||||
public convertSize(size: number | string, defaultValue?: string): string {
|
||||
defaultValue = defaultValue || '';
|
||||
if (types.isUndefinedOrNull(size)) {
|
||||
return defaultValue;
|
||||
|
||||
@@ -187,7 +187,7 @@ export default class DropDownComponent extends ComponentBase implements ICompone
|
||||
}
|
||||
|
||||
private get values(): string[] | sqlops.CategoryValue[] {
|
||||
return this.getPropertyOrDefault<sqlops.DropDownProperties, string[] | sqlops.CategoryValue[]>((props) => props.values, undefined);
|
||||
return this.getPropertyOrDefault<sqlops.DropDownProperties, string[] | sqlops.CategoryValue[]>((props) => props.values, []);
|
||||
}
|
||||
|
||||
private set values(newValue: string[] | sqlops.CategoryValue[]) {
|
||||
|
||||
@@ -45,7 +45,7 @@ class FormItem {
|
||||
template: `
|
||||
<div #container *ngIf="items" class="form-table" [style.padding]="getFormPadding()" [style.width]="getFormWidth()" [style.height]="getFormHeight()">
|
||||
<ng-container *ngFor="let item of items">
|
||||
<div class="form-row" *ngIf="isGroupLabel(item)">
|
||||
<div class="form-row" *ngIf="isGroupLabel(item)" [style.font-size]="getItemTitleFontSize(item)">
|
||||
<div class="form-item-row form-group-label">
|
||||
<model-component-wrapper [descriptor]="item.descriptor" [modelStore]="modelStore">
|
||||
</model-component-wrapper>
|
||||
@@ -56,7 +56,7 @@ class FormItem {
|
||||
<ng-container *ngIf="isHorizontal(item)">
|
||||
<div class="form-cell" [style.font-size]="getItemTitleFontSize(item)" [ngClass]="{'form-group-item': isInGroup(item)}">
|
||||
{{getItemTitle(item)}}<span class="form-required" *ngIf="isItemRequired(item)">*</span>
|
||||
<span class="icon info form-info" *ngIf="itemHasInfo(item)" [title]="getItemInfo(item)"></span>
|
||||
<span class="icon help form-info" *ngIf="itemHasInfo(item)" [title]="getItemInfo(item)"></span>
|
||||
</div>
|
||||
<div class="form-cell">
|
||||
<div class="form-component-container">
|
||||
@@ -76,7 +76,7 @@ class FormItem {
|
||||
<div class="form-vertical-container" *ngIf="isVertical(item)" [style.height]="getRowHeight(item)" [ngClass]="{'form-group-item': isInGroup(item)}">
|
||||
<div class="form-item-row" [style.font-size]="getItemTitleFontSize(item)">
|
||||
{{getItemTitle(item)}}<span class="form-required" *ngIf="isItemRequired(item)">*</span>
|
||||
<span class="icon info form-info" *ngIf="itemHasInfo(item)" [title]="getItemInfo(item)"></span>
|
||||
<span class="icon help form-info" *ngIf="itemHasInfo(item)" [title]="getItemInfo(item)"></span>
|
||||
</div>
|
||||
<div class="form-item-row" [style.width]="getComponentWidth(item)" [style.height]="getRowHeight(item)">
|
||||
<model-component-wrapper [descriptor]="item.descriptor" [modelStore]="modelStore" [style.width]="getComponentWidth(item)" [style.height]="getRowHeight(item)">
|
||||
@@ -179,8 +179,12 @@ export default class FormContainer extends ContainerBase<FormItemLayout> impleme
|
||||
}
|
||||
|
||||
private getItemTitleFontSize(item: FormItem): string {
|
||||
let defaultFontSize = '14px';
|
||||
if (this.isInGroup(item)) {
|
||||
defaultFontSize = '12px';
|
||||
}
|
||||
let itemConfig = item.config;
|
||||
return itemConfig && itemConfig.titleFontSize ? this.convertSize(itemConfig.titleFontSize, '11px') : '11px';
|
||||
return itemConfig && itemConfig.titleFontSize ? this.convertSize(itemConfig.titleFontSize, defaultFontSize) : defaultFontSize;
|
||||
}
|
||||
|
||||
private getActionComponents(item: FormItem): FormItem[] {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
|
||||
.form-vertical-container {
|
||||
padding-bottom: 15px;
|
||||
padding-bottom: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -57,11 +57,8 @@
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.form-group-item .form-item-row,
|
||||
.form-group-item.form-cell {
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
.form-group-label {
|
||||
padding-top: 3px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -12,14 +12,17 @@ import * as sqlops from 'sqlops';
|
||||
|
||||
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
||||
import { attachInputBoxStyler } from 'sql/common/theme/styler';
|
||||
|
||||
import { IInputOptions, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { attachInputBoxStyler, attachListStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import * as nls from 'vs/nls';
|
||||
import { inputBackground, inputBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import * as DomUtils from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
|
||||
@Component({
|
||||
selector: 'modelview-inputBox',
|
||||
@@ -73,11 +76,31 @@ export default class InputBoxComponent extends ComponentBase implements ICompone
|
||||
if (this._textareaContainer) {
|
||||
let textAreaInputOptions = Object.assign({}, inputOptions, { flexibleHeight: true, type: 'textarea' });
|
||||
this._textAreaInput = new InputBox(this._textareaContainer.nativeElement, this.contextViewService, textAreaInputOptions);
|
||||
this.onkeydown(this._textAreaInput.inputElement, (e: StandardKeyboardEvent) => {
|
||||
if (this.tryHandleKeyEvent(e)) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
// Else assume that keybinding service handles routing this to a command
|
||||
});
|
||||
|
||||
this.registerInput(this._textAreaInput, () => this.multiline);
|
||||
}
|
||||
this.inputElement.hideErrors = true;
|
||||
}
|
||||
|
||||
private onkeydown(domNode: HTMLElement, listener: (e: IKeyboardEvent) => void): void {
|
||||
this._register(DomUtils.addDisposableListener(domNode, DomUtils.EventType.KEY_DOWN, (e: KeyboardEvent) => listener(new StandardKeyboardEvent(e))));
|
||||
}
|
||||
|
||||
private tryHandleKeyEvent(e: StandardKeyboardEvent): boolean {
|
||||
let handled: boolean = false;
|
||||
|
||||
if (this.multiline && e.keyCode === KeyCode.Enter) {
|
||||
handled = true;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
private get inputElement(): InputBox {
|
||||
return this.multiline ? this._textAreaInput : this._input;
|
||||
}
|
||||
|
||||
@@ -74,15 +74,21 @@ export default class TableComponent extends ComponentBase implements IComponent,
|
||||
}
|
||||
}
|
||||
|
||||
transformData(rows: string[][], columns: any[]): { [key: string]: string }[] {
|
||||
return rows.map(row => {
|
||||
let object: { [key: string]: string } = {};
|
||||
row.forEach((val, index) => {
|
||||
let columnName: string = (columns[index].value) ? columns[index].value : <string>columns[index];
|
||||
object[columnName] = val;
|
||||
public static transformData(rows: string[][], columns: any[]): { [key: string]: string }[] {
|
||||
if (rows && columns) {
|
||||
return rows.map(row => {
|
||||
let object: { [key: string]: string } = {};
|
||||
if (row.forEach) {
|
||||
row.forEach((val, index) => {
|
||||
let columnName: string = (columns[index].value) ? columns[index].value : <string>columns[index];
|
||||
object[columnName] = val;
|
||||
});
|
||||
}
|
||||
return object;
|
||||
});
|
||||
return object;
|
||||
});
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
@@ -147,7 +153,7 @@ export default class TableComponent extends ComponentBase implements IComponent,
|
||||
public setProperties(properties: { [key: string]: any; }): void {
|
||||
super.setProperties(properties);
|
||||
this._tableData.clear();
|
||||
this._tableData.push(this.transformData(this.data, this.columns));
|
||||
this._tableData.push(TableComponent.transformData(this.data, this.columns));
|
||||
this._tableColumns = this.transformColumns(this.columns);
|
||||
this._table.columns = this._tableColumns;
|
||||
this._table.setData(this._tableData);
|
||||
|
||||
@@ -95,3 +95,7 @@ export class NodeType {
|
||||
public static ColumnMasterKey = 'ColumnMasterKey';
|
||||
public static ColumnEncryptionKey = 'ColumnEncryptionKey';
|
||||
}
|
||||
|
||||
export interface SqlThemeIcon {
|
||||
readonly id: string;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
'use strict';
|
||||
|
||||
import { NodeType } from 'sql/parts/objectExplorer/common/nodeType';
|
||||
import { TreeNode, TreeItemCollapsibleState, ObjectExplorerCallbacks } from 'sql/parts/objectExplorer/common/treeNode';
|
||||
import { TreeNode, TreeItemCollapsibleState } from 'sql/parts/objectExplorer/common/treeNode';
|
||||
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -20,7 +20,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { warn, error } from 'sql/base/common/log';
|
||||
import { ServerTreeView } from 'sql/parts/objectExplorer/viewlet/serverTreeView';
|
||||
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
export const SERVICE_ID = 'ObjectExplorerService';
|
||||
|
||||
@@ -162,10 +161,16 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
||||
error(expandResponse.errorMessage);
|
||||
}
|
||||
|
||||
let nodeStatus = this._sessions[expandResponse.sessionId].nodes[expandResponse.nodePath];
|
||||
if (nodeStatus && nodeStatus.expandEmitter) {
|
||||
nodeStatus.expandEmitter.fire(expandResponse);
|
||||
} else {
|
||||
let sessionStatus = this._sessions[expandResponse.sessionId];
|
||||
let foundSession = false;
|
||||
if (sessionStatus) {
|
||||
let nodeStatus = this._sessions[expandResponse.sessionId].nodes[expandResponse.nodePath];
|
||||
foundSession = !!nodeStatus;
|
||||
if (foundSession && nodeStatus.expandEmitter) {
|
||||
nodeStatus.expandEmitter.fire(expandResponse);
|
||||
}
|
||||
}
|
||||
if (!foundSession) {
|
||||
warn(`Cannot find node status for session: ${expandResponse.sessionId} and node path: ${expandResponse.nodePath}`);
|
||||
}
|
||||
}
|
||||
@@ -396,7 +401,7 @@ export class ObjectExplorerService implements IObjectExplorerService {
|
||||
}
|
||||
|
||||
return new TreeNode(nodeInfo.nodeType, nodeInfo.label, isLeaf, nodeInfo.nodePath,
|
||||
nodeInfo.nodeSubType, nodeInfo.nodeStatus, parent, nodeInfo.metadata, {
|
||||
nodeInfo.nodeSubType, nodeInfo.nodeStatus, parent, nodeInfo.metadata, nodeInfo.iconType, {
|
||||
getChildren: treeNode => this.getChildren(treeNode),
|
||||
isExpanded: treeNode => this.isExpanded(treeNode),
|
||||
setNodeExpandedState: (treeNode, expandedState) => this.setNodeExpandedState(treeNode, expandedState),
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
'use strict';
|
||||
|
||||
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
||||
import { NodeType } from 'sql/parts/objectExplorer/common/nodeType';
|
||||
import { NodeType, SqlThemeIcon } from 'sql/parts/objectExplorer/common/nodeType';
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
import * as UUID from 'vs/base/common/uuid';
|
||||
@@ -83,6 +83,23 @@ export class TreeNode {
|
||||
|
||||
public metadata: sqlops.ObjectMetadata;
|
||||
|
||||
public iconType: string | SqlThemeIcon;
|
||||
|
||||
constructor(nodeTypeId: string, label: string, isAlwaysLeaf: boolean, nodePath: string,
|
||||
nodeSubType: string, nodeStatus: string, parent: TreeNode, metadata: sqlops.ObjectMetadata,
|
||||
iconType: string | SqlThemeIcon,
|
||||
private _objectExplorerCallbacks: ObjectExplorerCallbacks) {
|
||||
this.nodeTypeId = nodeTypeId;
|
||||
this.label = label;
|
||||
this.isAlwaysLeaf = isAlwaysLeaf;
|
||||
this.nodePath = nodePath;
|
||||
this.parent = parent;
|
||||
this.metadata = metadata;
|
||||
this.iconType = iconType;
|
||||
this.id = UUID.generateUuid();
|
||||
this.nodeSubType = nodeSubType;
|
||||
this.nodeStatus = nodeStatus;
|
||||
}
|
||||
public getConnectionProfile(): ConnectionProfile {
|
||||
var currentNode: TreeNode = this;
|
||||
while (!currentNode.connection && currentNode.parent) {
|
||||
@@ -149,18 +166,4 @@ export class TreeNode {
|
||||
public setSelected(selected: boolean, clearOtherSelections?: boolean): Thenable<void> {
|
||||
return this._objectExplorerCallbacks.setNodeSelected(this, selected, clearOtherSelections);
|
||||
}
|
||||
|
||||
constructor(nodeTypeId: string, label: string, isAlwaysLeaf: boolean, nodePath: string,
|
||||
nodeSubType: string, nodeStatus: string, parent: TreeNode, metadata: sqlops.ObjectMetadata,
|
||||
private _objectExplorerCallbacks: ObjectExplorerCallbacks) {
|
||||
this.nodeTypeId = nodeTypeId;
|
||||
this.label = label;
|
||||
this.isAlwaysLeaf = isAlwaysLeaf;
|
||||
this.nodePath = nodePath;
|
||||
this.parent = parent;
|
||||
this.metadata = metadata;
|
||||
this.id = UUID.generateUuid();
|
||||
this.nodeSubType = nodeSubType;
|
||||
this.nodeStatus = nodeStatus;
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ export class RefreshAction extends Action {
|
||||
id: string,
|
||||
label: string,
|
||||
tree: ITree,
|
||||
private element: ConnectionProfile | TreeNode,
|
||||
private element: IConnectionProfile | TreeNode,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
|
||||
@IErrorMessageService private _errorMessageService: IErrorMessageService
|
||||
@@ -88,80 +88,31 @@ export class DisconnectConnectionAction extends Action {
|
||||
public static ID = 'objectExplorer.disconnect';
|
||||
public static LABEL = localize('DisconnectAction', 'Disconnect');
|
||||
|
||||
private _disposables: IDisposable[] = [];
|
||||
private _connectionProfile: ConnectionProfile;
|
||||
|
||||
private _container: HTMLElement;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
private _connectionProfile: ConnectionProfile,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
|
||||
@IErrorMessageService private _errorMessageService: IErrorMessageService
|
||||
) {
|
||||
super(id, label);
|
||||
const self = this;
|
||||
this._disposables.push(this._connectionManagementService.onConnect(() => {
|
||||
self.setLabel();
|
||||
})
|
||||
);
|
||||
this._disposables.push(this._connectionManagementService.onDisconnect((disconnectParams) => {
|
||||
if (this._connectionProfile) {
|
||||
this._connectionProfile.isDisconnecting = false;
|
||||
}
|
||||
self.setLabel();
|
||||
self._connectionManagementService.closeDashboard(disconnectParams.connectionUri);
|
||||
})
|
||||
);
|
||||
if (this._objectExplorerService && this._objectExplorerService.onUpdateObjectExplorerNodes) {
|
||||
this._disposables.push(this._objectExplorerService.onUpdateObjectExplorerNodes((args) => {
|
||||
self.removeSpinning(args.connection);
|
||||
if (args.errorMessage !== undefined) {
|
||||
self.showError(args.errorMessage);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private showError(errorMessage: string) {
|
||||
if (this._errorMessageService) {
|
||||
this._errorMessageService.showDialog(Severity.Error, '', errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private setLabel(): void {
|
||||
if (!this._connectionProfile) {
|
||||
this.label = 'Connect';
|
||||
return;
|
||||
}
|
||||
this.label = this._connectionManagementService.isProfileConnected(this._connectionProfile) ? 'Disconnect' : 'Connect';
|
||||
}
|
||||
|
||||
private removeSpinning(connection: IConnectionProfile): void {
|
||||
if (this._connectionProfile) {
|
||||
if (connection.id === this._connectionProfile.id && this._container) {
|
||||
ObjectExplorerActionUtilities.hideLoadingIcon(this._container, ObjectExplorerActionUtilities.connectionElementClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run(actionContext: ObjectExplorerActionsContext): TPromise<any> {
|
||||
return new TPromise<boolean>((resolve, reject) => {
|
||||
if (actionContext instanceof ObjectExplorerActionsContext) {
|
||||
//set objectExplorerTreeNode for context menu clicks
|
||||
this._connectionProfile = actionContext.connectionProfile;
|
||||
this._container = actionContext.container;
|
||||
resolve(true);
|
||||
}
|
||||
|
||||
if (!this._connectionProfile) {
|
||||
resolve(true);
|
||||
}
|
||||
if (this._connectionManagementService.isProfileConnected(this._connectionProfile)) {
|
||||
this._connectionProfile.isDisconnecting = true;
|
||||
let profileImpl = this._connectionProfile as ConnectionProfile;
|
||||
if (profileImpl) {
|
||||
profileImpl.isDisconnecting = true;
|
||||
}
|
||||
this._connectionManagementService.disconnect(this._connectionProfile).then((value) => {
|
||||
if (profileImpl) {
|
||||
profileImpl.isDisconnecting = false;
|
||||
}
|
||||
resolve(true);
|
||||
}
|
||||
).catch(disconnectError => {
|
||||
@@ -172,11 +123,6 @@ export class DisconnectConnectionAction extends Action {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
this._disposables = dispose(this._disposables);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -362,11 +308,11 @@ export class RecentConnectionsFilterAction extends Action {
|
||||
export class NewQueryAction extends Action {
|
||||
public static ID = 'registeredServers.newQuery';
|
||||
public static LABEL = localize('registeredServers.newQuery', 'New Query');
|
||||
private _connectionProfile: ConnectionProfile;
|
||||
get connectionProfile(): ConnectionProfile {
|
||||
private _connectionProfile: IConnectionProfile;
|
||||
get connectionProfile(): IConnectionProfile {
|
||||
return this._connectionProfile;
|
||||
}
|
||||
set connectionProfile(profile: ConnectionProfile) {
|
||||
set connectionProfile(profile: IConnectionProfile) {
|
||||
this._connectionProfile = profile;
|
||||
}
|
||||
|
||||
@@ -403,7 +349,7 @@ export class DeleteConnectionAction extends Action {
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
private element: ConnectionProfile | ConnectionProfileGroup,
|
||||
private element: IConnectionProfile | ConnectionProfileGroup,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
|
||||
) {
|
||||
super(id, label);
|
||||
@@ -413,7 +359,6 @@ export class DeleteConnectionAction extends Action {
|
||||
}
|
||||
|
||||
if (element instanceof ConnectionProfile) {
|
||||
element = <ConnectionProfile>element;
|
||||
let parent: ConnectionProfileGroup = element.parent;
|
||||
if (parent && parent.id === Constants.unsavedGroupId) {
|
||||
this.enabled = false;
|
||||
|
||||
@@ -8,11 +8,14 @@ import { localize } from 'vs/nls';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||
import { ExecuteCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
|
||||
import * as sqlops from 'sqlops';
|
||||
import { IConnectionManagementService, IConnectionCompletionOptions, IErrorMessageService } from 'sql/parts/connection/common/connectionManagement';
|
||||
import { TreeNode } from 'sql/parts/objectExplorer/common/treeNode';
|
||||
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
||||
import {
|
||||
NewQueryAction, ScriptSelectAction, EditDataAction, ScriptCreateAction,
|
||||
ScriptSelectAction, EditDataAction, ScriptCreateAction,
|
||||
ScriptExecuteAction, ScriptDeleteAction, ScriptAlterAction
|
||||
} from 'sql/workbench/common/actions';
|
||||
import { NodeType } from 'sql/parts/objectExplorer/common/nodeType';
|
||||
@@ -23,41 +26,51 @@ import { IScriptingService } from 'sql/services/scripting/scriptingService';
|
||||
import { IQueryEditorService } from 'sql/parts/query/common/queryEditorService';
|
||||
import { IObjectExplorerService } from 'sql/parts/objectExplorer/common/objectExplorerService';
|
||||
import * as Constants from 'sql/parts/connection/common/constants';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ExecuteCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
|
||||
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
|
||||
|
||||
export class ObjectExplorerActionsContext {
|
||||
public treeNode: TreeNode;
|
||||
public connectionProfile: ConnectionProfile;
|
||||
public container: HTMLElement;
|
||||
public tree: ITree;
|
||||
|
||||
export class ObjectExplorerActionsContext implements sqlops.ObjectExplorerContext {
|
||||
public connectionProfile: IConnectionProfile;
|
||||
public nodeInfo: sqlops.NodeInfo;
|
||||
public isConnectionNode: boolean = false;
|
||||
}
|
||||
|
||||
async function getTreeNode(context: ObjectExplorerActionsContext, objectExplorerService: IObjectExplorerService): TPromise<TreeNode> {
|
||||
if (context.isConnectionNode) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
return await objectExplorerService.getTreeNode(context.connectionProfile.id, context.nodeInfo.nodePath);
|
||||
}
|
||||
|
||||
|
||||
export class OEAction extends ExecuteCommandAction {
|
||||
private _objectExplorerTreeNode: TreeNode;
|
||||
private _container: HTMLElement;
|
||||
private _treeSelectionHandler: TreeSelectionHandler;
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService
|
||||
) {
|
||||
super(id, label, commandService);
|
||||
}
|
||||
|
||||
public run(actionContext: any): TPromise<boolean> {
|
||||
public async run(actionContext: any): TPromise<boolean> {
|
||||
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
|
||||
|
||||
|
||||
let profile: IConnectionProfile;
|
||||
if (actionContext.connectionProfile) {
|
||||
profile = actionContext.connectionProfile;
|
||||
} else {
|
||||
profile = TreeUpdateUtils.getConnectionProfile(<TreeNode>actionContext.treeNode);
|
||||
if (actionContext instanceof ObjectExplorerActionsContext) {
|
||||
if (actionContext.isConnectionNode) {
|
||||
profile = actionContext.connectionProfile;
|
||||
} else {
|
||||
// Get the "correct" version from the tree
|
||||
let treeNode = await getTreeNode(actionContext, this._objectExplorerService);
|
||||
profile = TreeUpdateUtils.getConnectionProfile(treeNode);
|
||||
}
|
||||
}
|
||||
this._treeSelectionHandler.onTreeActionStateChange(true);
|
||||
|
||||
@@ -72,18 +85,16 @@ export class ManageConnectionAction extends Action {
|
||||
public static ID = 'objectExplorer.manage';
|
||||
public static LABEL = localize('ManageAction', 'Manage');
|
||||
|
||||
private _connectionProfile: ConnectionProfile;
|
||||
private _objectExplorerTreeNode: TreeNode;
|
||||
private _treeSelectionHandler: TreeSelectionHandler;
|
||||
|
||||
protected _container: HTMLElement;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
private _tree: ITree,
|
||||
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
|
||||
@ICapabilitiesService protected _capabilitiesService: ICapabilitiesService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IObjectExplorerService private _objectExplorerService?: IObjectExplorerService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
@@ -91,33 +102,37 @@ export class ManageConnectionAction extends Action {
|
||||
run(actionContext: ObjectExplorerActionsContext): TPromise<any> {
|
||||
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
|
||||
this._treeSelectionHandler.onTreeActionStateChange(true);
|
||||
let self = this;
|
||||
let promise = new TPromise<boolean>((resolve, reject) => {
|
||||
this.doManage(actionContext).then((success) => {
|
||||
this.done();
|
||||
self.doManage(actionContext).then((success) => {
|
||||
self.done();
|
||||
resolve(success);
|
||||
}, error => {
|
||||
this.done();
|
||||
self.done();
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
private doManage(actionContext: ObjectExplorerActionsContext): Thenable<boolean> {
|
||||
private async doManage(actionContext: ObjectExplorerActionsContext): TPromise<boolean> {
|
||||
let treeNode: TreeNode = undefined;
|
||||
let connectionProfile: IConnectionProfile = undefined;
|
||||
if (actionContext instanceof ObjectExplorerActionsContext) {
|
||||
//set objectExplorerTreeNode for context menu clicks
|
||||
this._connectionProfile = actionContext.connectionProfile;
|
||||
this._objectExplorerTreeNode = actionContext.treeNode;
|
||||
if (this._connectionProfile === undefined && TreeUpdateUtils.isDatabaseNode(this._objectExplorerTreeNode)) {
|
||||
this._connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
|
||||
// Must use a real connection profile for this action due to lookup
|
||||
connectionProfile = ConnectionProfile.fromIConnectionProfile(this._capabilitiesService, actionContext.connectionProfile);
|
||||
if (!actionContext.isConnectionNode) {
|
||||
treeNode = await getTreeNode(actionContext, this._objectExplorerService);
|
||||
if (TreeUpdateUtils.isDatabaseNode(treeNode)) {
|
||||
connectionProfile = TreeUpdateUtils.getConnectionProfile(treeNode);
|
||||
}
|
||||
}
|
||||
this._container = actionContext.container;
|
||||
}
|
||||
|
||||
if (!this._connectionProfile) {
|
||||
if (!connectionProfile) {
|
||||
// This should never happen. There should be always a valid connection if the manage action is called for
|
||||
// an OE node or a database node
|
||||
return TPromise.wrap(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
let options: IConnectionCompletionOptions = {
|
||||
@@ -130,10 +145,10 @@ export class ManageConnectionAction extends Action {
|
||||
|
||||
// If it's a database node just open a database connection and open dashboard,
|
||||
// the node is already from an open OE session we don't need to create new session
|
||||
if (TreeUpdateUtils.isAvailableDatabaseNode(this._objectExplorerTreeNode)) {
|
||||
return this._connectionManagementService.showDashboard(this._connectionProfile);
|
||||
if (TreeUpdateUtils.isAvailableDatabaseNode(treeNode)) {
|
||||
return this._connectionManagementService.showDashboard(connectionProfile);
|
||||
} else {
|
||||
return TreeUpdateUtils.connectAndCreateOeSession(this._connectionProfile, options, this._connectionManagementService, this._objectExplorerService, actionContext.tree);
|
||||
return TreeUpdateUtils.connectAndCreateOeSession(connectionProfile, options, this._connectionManagementService, this._objectExplorerService, this._tree);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +164,6 @@ export class ManageConnectionAction extends Action {
|
||||
export class OEScriptSelectAction extends ScriptSelectAction {
|
||||
public static ID = 'objectExplorer.' + ScriptSelectAction.ID;
|
||||
private _objectExplorerTreeNode: TreeNode;
|
||||
private _container: HTMLElement;
|
||||
private _treeSelectionHandler: TreeSelectionHandler;
|
||||
|
||||
constructor(
|
||||
@@ -157,23 +171,23 @@ export class OEScriptSelectAction extends ScriptSelectAction {
|
||||
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
|
||||
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
|
||||
@IScriptingService protected _scriptingService: IScriptingService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService
|
||||
) {
|
||||
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService);
|
||||
}
|
||||
|
||||
public run(actionContext: any): TPromise<boolean> {
|
||||
public async run(actionContext: any): TPromise<boolean> {
|
||||
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
|
||||
if (actionContext instanceof ObjectExplorerActionsContext) {
|
||||
//set objectExplorerTreeNode for context menu clicks
|
||||
this._objectExplorerTreeNode = actionContext.treeNode;
|
||||
this._container = actionContext.container;
|
||||
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
|
||||
}
|
||||
this._treeSelectionHandler.onTreeActionStateChange(true);
|
||||
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
|
||||
var connectionProfile = TreeUpdateUtils.getConnectionProfile(this._objectExplorerTreeNode);
|
||||
var ownerUri = this._connectionManagementService.getConnectionId(connectionProfile);
|
||||
ownerUri = this._connectionManagementService.getFormattedUri(ownerUri, connectionProfile);
|
||||
var metadata = (<TreeNode>this._objectExplorerTreeNode).metadata;
|
||||
var metadata = this._objectExplorerTreeNode.metadata;
|
||||
|
||||
return super.run({ profile: connectionProfile, object: metadata }).then((result) => {
|
||||
this._treeSelectionHandler.onTreeActionStateChange(false);
|
||||
@@ -185,7 +199,6 @@ export class OEScriptSelectAction extends ScriptSelectAction {
|
||||
export class OEEditDataAction extends EditDataAction {
|
||||
public static ID = 'objectExplorer.' + EditDataAction.ID;
|
||||
private _objectExplorerTreeNode: TreeNode;
|
||||
private _container: HTMLElement;
|
||||
private _treeSelectionHandler: TreeSelectionHandler;
|
||||
|
||||
constructor(
|
||||
@@ -193,17 +206,17 @@ export class OEEditDataAction extends EditDataAction {
|
||||
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
|
||||
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
|
||||
@IScriptingService protected _scriptingService: IScriptingService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService
|
||||
) {
|
||||
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService);
|
||||
}
|
||||
|
||||
public run(actionContext: any): TPromise<boolean> {
|
||||
public async run(actionContext: any): TPromise<boolean> {
|
||||
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
|
||||
if (actionContext instanceof ObjectExplorerActionsContext) {
|
||||
//set objectExplorerTreeNode for context menu clicks
|
||||
this._objectExplorerTreeNode = actionContext.treeNode;
|
||||
this._container = actionContext.container;
|
||||
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
|
||||
}
|
||||
this._treeSelectionHandler.onTreeActionStateChange(true);
|
||||
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
|
||||
@@ -219,7 +232,6 @@ export class OEEditDataAction extends EditDataAction {
|
||||
export class OEScriptCreateAction extends ScriptCreateAction {
|
||||
public static ID = 'objectExplorer.' + ScriptCreateAction.ID;
|
||||
private _objectExplorerTreeNode: TreeNode;
|
||||
private _container: HTMLElement;
|
||||
private _treeSelectionHandler: TreeSelectionHandler;
|
||||
|
||||
constructor(
|
||||
@@ -227,18 +239,18 @@ export class OEScriptCreateAction extends ScriptCreateAction {
|
||||
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
|
||||
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
|
||||
@IScriptingService protected _scriptingService: IScriptingService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IErrorMessageService protected _errorMessageService: IErrorMessageService
|
||||
) {
|
||||
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService, _errorMessageService);
|
||||
}
|
||||
|
||||
public run(actionContext: any): TPromise<boolean> {
|
||||
public async run(actionContext: any): TPromise<boolean> {
|
||||
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
|
||||
if (actionContext instanceof ObjectExplorerActionsContext) {
|
||||
//set objectExplorerTreeNode for context menu clicks
|
||||
this._objectExplorerTreeNode = actionContext.treeNode;
|
||||
this._container = actionContext.container;
|
||||
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
|
||||
}
|
||||
this._treeSelectionHandler.onTreeActionStateChange(true);
|
||||
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
|
||||
@@ -256,7 +268,6 @@ export class OEScriptCreateAction extends ScriptCreateAction {
|
||||
export class OEScriptExecuteAction extends ScriptExecuteAction {
|
||||
public static ID = 'objectExplorer.' + ScriptExecuteAction.ID;
|
||||
private _objectExplorerTreeNode: TreeNode;
|
||||
private _container: HTMLElement;
|
||||
private _treeSelectionHandler: TreeSelectionHandler;
|
||||
|
||||
constructor(
|
||||
@@ -264,18 +275,18 @@ export class OEScriptExecuteAction extends ScriptExecuteAction {
|
||||
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
|
||||
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
|
||||
@IScriptingService protected _scriptingService: IScriptingService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IErrorMessageService protected _errorMessageService: IErrorMessageService
|
||||
) {
|
||||
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService, _errorMessageService);
|
||||
}
|
||||
|
||||
public run(actionContext: any): TPromise<boolean> {
|
||||
public async run(actionContext: any): TPromise<boolean> {
|
||||
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
|
||||
if (actionContext instanceof ObjectExplorerActionsContext) {
|
||||
//set objectExplorerTreeNode for context menu clicks
|
||||
this._objectExplorerTreeNode = actionContext.treeNode;
|
||||
this._container = actionContext.container;
|
||||
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
|
||||
}
|
||||
this._treeSelectionHandler.onTreeActionStateChange(true);
|
||||
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
|
||||
@@ -293,7 +304,6 @@ export class OEScriptExecuteAction extends ScriptExecuteAction {
|
||||
export class OEScriptAlterAction extends ScriptAlterAction {
|
||||
public static ID = 'objectExplorer.' + ScriptAlterAction.ID;
|
||||
private _objectExplorerTreeNode: TreeNode;
|
||||
private _container: HTMLElement;
|
||||
private _treeSelectionHandler: TreeSelectionHandler;
|
||||
|
||||
constructor(
|
||||
@@ -301,18 +311,18 @@ export class OEScriptAlterAction extends ScriptAlterAction {
|
||||
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
|
||||
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
|
||||
@IScriptingService protected _scriptingService: IScriptingService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IErrorMessageService protected _errorMessageService: IErrorMessageService
|
||||
) {
|
||||
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService, _errorMessageService);
|
||||
}
|
||||
|
||||
public run(actionContext: any): TPromise<boolean> {
|
||||
public async run(actionContext: any): TPromise<boolean> {
|
||||
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
|
||||
if (actionContext instanceof ObjectExplorerActionsContext) {
|
||||
//set objectExplorerTreeNode for context menu clicks
|
||||
this._objectExplorerTreeNode = actionContext.treeNode;
|
||||
this._container = actionContext.container;
|
||||
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
|
||||
}
|
||||
this._treeSelectionHandler.onTreeActionStateChange(true);
|
||||
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
|
||||
@@ -330,7 +340,6 @@ export class OEScriptAlterAction extends ScriptAlterAction {
|
||||
export class OEScriptDeleteAction extends ScriptDeleteAction {
|
||||
public static ID = 'objectExplorer.' + ScriptDeleteAction.ID;
|
||||
private _objectExplorerTreeNode: TreeNode;
|
||||
private _container: HTMLElement;
|
||||
private _treeSelectionHandler: TreeSelectionHandler;
|
||||
|
||||
constructor(
|
||||
@@ -338,18 +347,18 @@ export class OEScriptDeleteAction extends ScriptDeleteAction {
|
||||
@IQueryEditorService protected _queryEditorService: IQueryEditorService,
|
||||
@IConnectionManagementService protected _connectionManagementService: IConnectionManagementService,
|
||||
@IScriptingService protected _scriptingService: IScriptingService,
|
||||
@IObjectExplorerService private _objectExplorerService: IObjectExplorerService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IErrorMessageService protected _errorMessageService: IErrorMessageService
|
||||
) {
|
||||
super(id, label, _queryEditorService, _connectionManagementService, _scriptingService, _errorMessageService);
|
||||
}
|
||||
|
||||
public run(actionContext: any): TPromise<boolean> {
|
||||
public async run(actionContext: any): TPromise<boolean> {
|
||||
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
|
||||
if (actionContext instanceof ObjectExplorerActionsContext) {
|
||||
//set objectExplorerTreeNode for context menu clicks
|
||||
this._objectExplorerTreeNode = actionContext.treeNode;
|
||||
this._container = actionContext.container;
|
||||
this._objectExplorerTreeNode = await getTreeNode(actionContext, this._objectExplorerService);
|
||||
}
|
||||
this._treeSelectionHandler.onTreeActionStateChange(true);
|
||||
var connectionProfile = TreeUpdateUtils.getConnectionProfile(<TreeNode>this._objectExplorerTreeNode);
|
||||
@@ -364,77 +373,11 @@ export class OEScriptDeleteAction extends ScriptDeleteAction {
|
||||
}
|
||||
}
|
||||
|
||||
export class DisconnectAction extends Action {
|
||||
public static ID = 'objectExplorer.disconnect';
|
||||
public static LABEL = localize('objectExplorAction.disconnect', 'Disconnect');
|
||||
private _objectExplorerTreeNode: TreeNode;
|
||||
private _container: HTMLElement;
|
||||
private _treeSelectionHandler: TreeSelectionHandler;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IConnectionManagementService private connectionManagementService: IConnectionManagementService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(actionContext: any): TPromise<boolean> {
|
||||
this._treeSelectionHandler = this._instantiationService.createInstance(TreeSelectionHandler);
|
||||
if (actionContext instanceof ObjectExplorerActionsContext) {
|
||||
//set objectExplorerTreeNode for context menu clicks
|
||||
this._objectExplorerTreeNode = actionContext.treeNode;
|
||||
this._container = actionContext.container;
|
||||
}
|
||||
|
||||
var connectionProfile = (<TreeNode>this._objectExplorerTreeNode).getConnectionProfile();
|
||||
if (this.connectionManagementService.isProfileConnected(connectionProfile)) {
|
||||
this._treeSelectionHandler.onTreeActionStateChange(true);
|
||||
|
||||
this.connectionManagementService.disconnect(connectionProfile).then(() => {
|
||||
this._treeSelectionHandler.onTreeActionStateChange(false);
|
||||
});
|
||||
}
|
||||
|
||||
return TPromise.as(true);
|
||||
}
|
||||
}
|
||||
|
||||
export class ObjectExplorerActionUtilities {
|
||||
|
||||
public static readonly objectExplorerElementClass = 'object-element-group';
|
||||
public static readonly connectionElementClass = 'connection-tile';
|
||||
|
||||
|
||||
private static getGroupContainer(container: HTMLElement, elementName: string): HTMLElement {
|
||||
var element = container;
|
||||
while (element && element.className !== elementName) {
|
||||
element = element.parentElement;
|
||||
}
|
||||
return element ? element.parentElement : undefined;
|
||||
}
|
||||
|
||||
public static showLoadingIcon(container: HTMLElement, elementName: string): void {
|
||||
if (container) {
|
||||
let groupContainer = this.getGroupContainer(container, elementName);
|
||||
if (groupContainer) {
|
||||
groupContainer.classList.add('icon');
|
||||
groupContainer.classList.add('in-progress');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static hideLoadingIcon(container: HTMLElement, elementName: string): void {
|
||||
if (container) {
|
||||
let element = this.getGroupContainer(container, elementName);
|
||||
if (element && element.classList) {
|
||||
element.classList.remove('icon');
|
||||
element.classList.remove('in-progress');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static getScriptMap(treeNode: TreeNode): Map<NodeType, any[]> {
|
||||
let scriptMap = new Map<NodeType, any[]>();
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||
import { ContributableActionProvider } from 'vs/workbench/browser/actions';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem';
|
||||
|
||||
import {
|
||||
DisconnectConnectionAction, AddServerAction,
|
||||
@@ -16,9 +18,7 @@ import {
|
||||
}
|
||||
from 'sql/parts/objectExplorer/viewlet/connectionTreeAction';
|
||||
import {
|
||||
DisconnectAction, ObjectExplorerActionUtilities,
|
||||
ManageConnectionAction,
|
||||
OEAction
|
||||
ObjectExplorerActionUtilities, ManageConnectionAction, OEAction
|
||||
} from 'sql/parts/objectExplorer/viewlet/objectExplorerActions';
|
||||
import { TreeNode } from 'sql/parts/objectExplorer/common/treeNode';
|
||||
import { NodeType } from 'sql/parts/objectExplorer/common/nodeType';
|
||||
@@ -27,8 +27,14 @@ import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile
|
||||
import { NewProfilerAction } from 'sql/parts/profiler/contrib/profilerActions';
|
||||
import { TreeUpdateUtils } from 'sql/parts/objectExplorer/viewlet/treeUpdateUtils';
|
||||
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
|
||||
import { ExecuteCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { MenuId, IMenuService } from 'vs/platform/actions/common/actions';
|
||||
import { NewQueryAction } from 'sql/workbench/common/actions';
|
||||
import { ConnectionContextKey } from 'sql/parts/connection/common/connectionContextKey';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { TreeNodeContextKey } from './treeNodeContextKey';
|
||||
import { IQueryManagementService } from 'sql/parts/query/common/queryManagement';
|
||||
import { IScriptingService } from 'sql/services/scripting/scriptingService';
|
||||
import * as constants from 'sql/common/constants';
|
||||
|
||||
/**
|
||||
* Provides actions for the server tree elements
|
||||
@@ -37,7 +43,12 @@ export class ServerTreeActionProvider extends ContributableActionProvider {
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@IQueryManagementService private _queryManagementService: IQueryManagementService,
|
||||
@IScriptingService private _scriptingService: IScriptingService,
|
||||
@IContextMenuService private contextMenuService: IContextMenuService,
|
||||
@IMenuService private menuService: IMenuService,
|
||||
@IContextKeyService private _contextKeyService: IContextKeyService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -57,8 +68,11 @@ export class ServerTreeActionProvider extends ContributableActionProvider {
|
||||
return TPromise.as(this.getConnectionProfileGroupActions(tree, element));
|
||||
}
|
||||
if (element instanceof TreeNode) {
|
||||
var treeNode = <TreeNode>element;
|
||||
return TPromise.as(this.getObjectExplorerNodeActions(tree, treeNode));
|
||||
return TPromise.as(this.getObjectExplorerNodeActions({
|
||||
tree: tree,
|
||||
profile: element.getConnectionProfile(),
|
||||
treeNode: element
|
||||
}));
|
||||
}
|
||||
|
||||
return TPromise.as([]);
|
||||
@@ -75,23 +89,58 @@ export class ServerTreeActionProvider extends ContributableActionProvider {
|
||||
/**
|
||||
* Return actions for connection elements
|
||||
*/
|
||||
public getConnectionActions(tree: ITree, element: ConnectionProfile): IAction[] {
|
||||
let actions: IAction[] = [];
|
||||
actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL));
|
||||
actions.push(this._instantiationService.createInstance(OEAction, NewQueryAction.ID, NewQueryAction.LABEL));
|
||||
if (this._connectionManagementService.isProfileConnected(element)) {
|
||||
actions.push(this._instantiationService.createInstance(DisconnectConnectionAction, DisconnectConnectionAction.ID, DisconnectConnectionAction.LABEL));
|
||||
}
|
||||
actions.push(this._instantiationService.createInstance(DeleteConnectionAction, DeleteConnectionAction.ID, DeleteConnectionAction.DELETE_CONNECTION_LABEL, element));
|
||||
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, tree, element));
|
||||
public getConnectionActions(tree: ITree, profile: ConnectionProfile): IAction[] {
|
||||
return this.getAllActions({
|
||||
tree: tree,
|
||||
profile: profile
|
||||
}, (context) => this.getBuiltinConnectionActions(context));
|
||||
}
|
||||
|
||||
if (process.env['VSCODE_DEV']) {
|
||||
private getAllActions(context: ObjectExplorerContext, getDefaultActions: (ObjectExplorerContext) => IAction[]) {
|
||||
// Create metadata needed to get a useful set of actions
|
||||
let scopedContextService = this.getContextKeyService(context);
|
||||
let menu = this.menuService.createMenu(MenuId.ObjectExplorerItemContext, scopedContextService);
|
||||
|
||||
// Fill in all actions
|
||||
let actions = getDefaultActions(context);
|
||||
fillInActions(menu, { arg: undefined, shouldForwardArgs: true }, actions, this.contextMenuService);
|
||||
|
||||
// Cleanup
|
||||
scopedContextService.dispose();
|
||||
menu.dispose();
|
||||
return actions;
|
||||
|
||||
}
|
||||
|
||||
private getBuiltinConnectionActions(context: ObjectExplorerContext): IAction[] {
|
||||
let actions: IAction[] = [];
|
||||
actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL, context.tree));
|
||||
this.addNewQueryAction(context, actions);
|
||||
|
||||
if (this._connectionManagementService.isProfileConnected(context.profile)) {
|
||||
actions.push(this._instantiationService.createInstance(DisconnectConnectionAction, DisconnectConnectionAction.ID, DisconnectConnectionAction.LABEL, context.profile));
|
||||
}
|
||||
actions.push(this._instantiationService.createInstance(DeleteConnectionAction, DeleteConnectionAction.ID, DeleteConnectionAction.DELETE_CONNECTION_LABEL, context.profile));
|
||||
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, context.tree, context.profile));
|
||||
|
||||
if (process.env['VSCODE_DEV'] && constants.MssqlProviderId === context.profile.providerName) {
|
||||
actions.push(this._instantiationService.createInstance(OEAction, NewProfilerAction.ID, NewProfilerAction.LABEL));
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
private getContextKeyService(context: ObjectExplorerContext): IContextKeyService {
|
||||
let scopedContextService = this._contextKeyService.createScoped();
|
||||
let connectionContextKey = new ConnectionContextKey(scopedContextService);
|
||||
connectionContextKey.set(context.profile);
|
||||
let treeNodeContextKey = new TreeNodeContextKey(scopedContextService);
|
||||
if (context.treeNode) {
|
||||
treeNodeContextKey.set(context.treeNode);
|
||||
}
|
||||
return scopedContextService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return actions for connection group elements
|
||||
*/
|
||||
@@ -106,32 +155,50 @@ export class ServerTreeActionProvider extends ContributableActionProvider {
|
||||
/**
|
||||
* Return actions for OE elements
|
||||
*/
|
||||
public getObjectExplorerNodeActions(tree: ITree, treeNode: TreeNode): IAction[] {
|
||||
let actions = [];
|
||||
private getObjectExplorerNodeActions(context: ObjectExplorerContext): IAction[] {
|
||||
return this.getAllActions(context, (context) => this.getBuiltInNodeActions(context));
|
||||
}
|
||||
|
||||
private getBuiltInNodeActions(context: ObjectExplorerContext): IAction[] {
|
||||
let actions: IAction[] = [];
|
||||
let treeNode = context.treeNode;
|
||||
if (TreeUpdateUtils.isDatabaseNode(treeNode)) {
|
||||
if (TreeUpdateUtils.isAvailableDatabaseNode(treeNode)) {
|
||||
actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL));
|
||||
actions.push(this._instantiationService.createInstance(ManageConnectionAction, ManageConnectionAction.ID, ManageConnectionAction.LABEL, context.tree));
|
||||
} else {
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
actions.push(this._instantiationService.createInstance(OEAction, NewQueryAction.ID, NewQueryAction.LABEL));
|
||||
let scriptMap: Map<NodeType, any[]> = ObjectExplorerActionUtilities.getScriptMap(treeNode);
|
||||
let supportedActions = scriptMap.get(treeNode.nodeTypeId);
|
||||
let self = this;
|
||||
|
||||
if (supportedActions !== null && supportedActions !== undefined) {
|
||||
supportedActions.forEach(action => {
|
||||
actions.push(self._instantiationService.createInstance(action, action.ID, action.LABEL));
|
||||
});
|
||||
}
|
||||
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, tree, treeNode));
|
||||
|
||||
|
||||
if (treeNode.isTopLevel()) {
|
||||
actions.push(this._instantiationService.createInstance(DisconnectAction, DisconnectAction.ID, DisconnectAction.LABEL));
|
||||
}
|
||||
this.addNewQueryAction(context, actions);
|
||||
this.addScriptingActions(context, actions);
|
||||
actions.push(this._instantiationService.createInstance(RefreshAction, RefreshAction.ID, RefreshAction.LABEL, context.tree, treeNode));
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
private addNewQueryAction(context: ObjectExplorerContext, actions: IAction[]): void {
|
||||
if (this._queryManagementService.isProviderRegistered(context.profile.providerName)) {
|
||||
actions.push(this._instantiationService.createInstance(OEAction, NewQueryAction.ID, NewQueryAction.LABEL));
|
||||
}
|
||||
}
|
||||
|
||||
private addScriptingActions(context: ObjectExplorerContext, actions: IAction[]): void {
|
||||
if (this._scriptingService.isProviderRegistered(context.profile.providerName)) {
|
||||
let scriptMap: Map<NodeType, any[]> = ObjectExplorerActionUtilities.getScriptMap(context.treeNode);
|
||||
let supportedActions = scriptMap.get(context.treeNode.nodeTypeId);
|
||||
let self = this;
|
||||
if (supportedActions !== null && supportedActions !== undefined) {
|
||||
supportedActions.forEach(action => {
|
||||
actions.push(self._instantiationService.createInstance(action, action.ID, action.LABEL));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface ObjectExplorerContext {
|
||||
tree: ITree;
|
||||
profile: ConnectionProfile;
|
||||
treeNode?: TreeNode;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { ServerTreeActionProvider } from 'sql/parts/objectExplorer/viewlet/serve
|
||||
import { ObjectExplorerActionsContext } from 'sql/parts/objectExplorer/viewlet/objectExplorerActions';
|
||||
import { TreeNode } from 'sql/parts/objectExplorer/common/treeNode';
|
||||
import { OpenMode } from 'vs/base/parts/tree/browser/treeDefaults';
|
||||
import { TreeUpdateUtils } from 'sql/parts/objectExplorer/viewlet/treeUpdateUtils';
|
||||
|
||||
/**
|
||||
* Extends the tree controller to handle clicks on the tree elements
|
||||
@@ -73,26 +74,24 @@ export class ServerTreeController extends treedefaults.DefaultController {
|
||||
event.stopPropagation();
|
||||
|
||||
tree.setFocus(element);
|
||||
let parent: ConnectionProfileGroup = undefined;
|
||||
if (element instanceof ConnectionProfileGroup) {
|
||||
parent = <ConnectionProfileGroup>element;
|
||||
}
|
||||
else if (element instanceof ConnectionProfile) {
|
||||
parent = (<ConnectionProfile>element).parent;
|
||||
}
|
||||
|
||||
var actionContext: any;
|
||||
if (element instanceof TreeNode) {
|
||||
actionContext = new ObjectExplorerActionsContext();
|
||||
actionContext.container = event.target;
|
||||
actionContext.treeNode = <TreeNode>element;
|
||||
actionContext.tree = tree;
|
||||
let context = new ObjectExplorerActionsContext();
|
||||
context.nodeInfo = element.toNodeInfo();
|
||||
// Note: getting DB name before, but intentionally not using treeUpdateUtils.getConnectionProfile as it replaces
|
||||
// the connection ID with a new one. This breaks a number of internal tasks
|
||||
context.connectionProfile = element.getConnectionProfile().toIConnectionProfile();
|
||||
context.connectionProfile.databaseName = element.getDatabaseName();
|
||||
actionContext = context;
|
||||
} else if (element instanceof ConnectionProfile) {
|
||||
actionContext = new ObjectExplorerActionsContext();
|
||||
actionContext.container = event.target;
|
||||
actionContext.connectionProfile = <ConnectionProfile>element;
|
||||
actionContext.tree = tree;
|
||||
let context = new ObjectExplorerActionsContext();
|
||||
context.connectionProfile = element.toIConnectionProfile();
|
||||
context.isConnectionNode = true;
|
||||
actionContext = context;
|
||||
} else {
|
||||
// TODO: because the connection group is used as a context object and isn't serializable,
|
||||
// the Group-level context menu is not currently extensible
|
||||
actionContext = element;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,12 +31,10 @@ export class ServerTreeDataSource implements IDataSource {
|
||||
* No more than one element may use a given identifier.
|
||||
*/
|
||||
public getId(tree: ITree, element: any): string {
|
||||
if (element instanceof ConnectionProfile) {
|
||||
return (<ConnectionProfile>element).id;
|
||||
} else if (element instanceof ConnectionProfileGroup) {
|
||||
return (<ConnectionProfileGroup>element).id;
|
||||
} else if (element instanceof TreeNode) {
|
||||
return (<TreeNode>element).id;
|
||||
if (element instanceof ConnectionProfile
|
||||
|| element instanceof ConnectionProfileGroup
|
||||
|| element instanceof TreeNode) {
|
||||
return element.id;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
@@ -49,9 +47,9 @@ export class ServerTreeDataSource implements IDataSource {
|
||||
if (element instanceof ConnectionProfile) {
|
||||
return true;
|
||||
} else if (element instanceof ConnectionProfileGroup) {
|
||||
return (<ConnectionProfileGroup>element).hasChildren();
|
||||
return element.hasChildren();
|
||||
} else if (element instanceof TreeNode) {
|
||||
return !(<TreeNode>element).isAlwaysLeaf;
|
||||
return !element.isAlwaysLeaf;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -70,7 +68,7 @@ export class ServerTreeDataSource implements IDataSource {
|
||||
} else if (element instanceof ConnectionProfileGroup) {
|
||||
resolve((<ConnectionProfileGroup>element).getChildren());
|
||||
} else if (element instanceof TreeNode) {
|
||||
var node = <TreeNode>element;
|
||||
var node = element;
|
||||
if (node.children) {
|
||||
resolve(node.children);
|
||||
} else {
|
||||
@@ -92,11 +90,11 @@ export class ServerTreeDataSource implements IDataSource {
|
||||
*/
|
||||
public getParent(tree: ITree, element: any): TPromise<any> {
|
||||
if (element instanceof ConnectionProfile) {
|
||||
return TPromise.as((<ConnectionProfile>element).getParent());
|
||||
return TPromise.as(element.getParent());
|
||||
} else if (element instanceof ConnectionProfileGroup) {
|
||||
return TPromise.as((<ConnectionProfileGroup>element).getParent());
|
||||
return TPromise.as(element.getParent());
|
||||
} else if (element instanceof TreeNode) {
|
||||
return TPromise.as(TreeUpdateUtils.getObjectExplorerParent(<TreeNode>element, this._connectionManagementService));
|
||||
return TPromise.as(TreeUpdateUtils.getObjectExplorerParent(element, this._connectionManagementService));
|
||||
} else {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
@@ -105,38 +105,45 @@ export class ServerTreeRenderer implements IRenderer {
|
||||
*/
|
||||
public renderElement(tree: ITree, element: any, templateId: string, templateData: any): void {
|
||||
if (templateId === ServerTreeRenderer.CONNECTION_TEMPLATE_ID) {
|
||||
this.renderConnection(tree, element, templateData);
|
||||
this.renderConnection(element, templateData);
|
||||
} else if (templateId === ServerTreeRenderer.CONNECTION_GROUP_TEMPLATE_ID) {
|
||||
this.renderConnectionProfileGroup(tree, element, templateData);
|
||||
this.renderConnectionProfileGroup(element, templateData);
|
||||
} else {
|
||||
this.renderObjectExplorer(tree, element, templateData);
|
||||
this.renderObjectExplorer(element, templateData);
|
||||
}
|
||||
}
|
||||
|
||||
private renderObjectExplorer(tree: ITree, treeNode: TreeNode, templateData: IObjectExplorerTemplateData): void {
|
||||
var iconName = treeNode.nodeTypeId;
|
||||
if (treeNode.nodeStatus) {
|
||||
iconName = treeNode.nodeTypeId + '_' + treeNode.nodeStatus;
|
||||
}
|
||||
if (treeNode.nodeSubType) {
|
||||
iconName = treeNode.nodeTypeId + '_' + treeNode.nodeSubType;
|
||||
private renderObjectExplorer(treeNode: TreeNode, templateData: IObjectExplorerTemplateData): void {
|
||||
// Use an explicitly defined iconType first. If not defined, fall back to using nodeType and
|
||||
// other compount indicators instead.
|
||||
let iconName: string = undefined;
|
||||
if (treeNode.iconType) {
|
||||
iconName = (typeof treeNode.iconType === 'string') ? treeNode.iconType : treeNode.iconType.id;
|
||||
} else {
|
||||
iconName = treeNode.nodeTypeId;
|
||||
if (treeNode.nodeStatus) {
|
||||
iconName = treeNode.nodeTypeId + '_' + treeNode.nodeStatus;
|
||||
}
|
||||
if (treeNode.nodeSubType) {
|
||||
iconName = treeNode.nodeTypeId + '_' + treeNode.nodeSubType;
|
||||
}
|
||||
}
|
||||
|
||||
let tokens: string[] = [];
|
||||
for (var index = 1; index < templateData.icon.classList.length; index++) {
|
||||
for (let index = 1; index < templateData.icon.classList.length; index++) {
|
||||
tokens.push(templateData.icon.classList.item(index));
|
||||
}
|
||||
templateData.icon.classList.remove(...tokens);
|
||||
templateData.icon.classList.add('icon');
|
||||
let iconLoweCaseName = iconName.toLocaleLowerCase();
|
||||
templateData.icon.classList.add(iconLoweCaseName);
|
||||
let iconLowerCaseName = iconName.toLocaleLowerCase();
|
||||
templateData.icon.classList.add(iconLowerCaseName);
|
||||
|
||||
templateData.label.textContent = treeNode.label;
|
||||
templateData.root.title = treeNode.label;
|
||||
}
|
||||
|
||||
|
||||
private renderConnection(tree: ITree, connection: ConnectionProfile, templateData: IConnectionTemplateData): void {
|
||||
private renderConnection(connection: ConnectionProfile, templateData: IConnectionTemplateData): void {
|
||||
if (!this._isCompact) {
|
||||
if (this._connectionManagementService.isConnected(undefined, connection)) {
|
||||
templateData.icon.classList.remove('disconnected');
|
||||
@@ -157,9 +164,9 @@ export class ServerTreeRenderer implements IRenderer {
|
||||
templateData.connectionProfile = connection;
|
||||
}
|
||||
|
||||
private renderConnectionProfileGroup(tree: ITree, connectionProfileGroup: ConnectionProfileGroup, templateData: IConnectionProfileGroupTemplateData): void {
|
||||
private renderConnectionProfileGroup(connectionProfileGroup: ConnectionProfileGroup, templateData: IConnectionProfileGroupTemplateData): void {
|
||||
|
||||
var rowElement = this.findParentElement(templateData.root, 'monaco-tree-row');
|
||||
let rowElement = this.findParentElement(templateData.root, 'monaco-tree-row');
|
||||
if (rowElement) {
|
||||
if (connectionProfileGroup.color) {
|
||||
rowElement.style.background = connectionProfileGroup.color;
|
||||
@@ -179,7 +186,7 @@ export class ServerTreeRenderer implements IRenderer {
|
||||
* Returns the first parent which contains the className
|
||||
*/
|
||||
private findParentElement(container: HTMLElement, className: string): HTMLElement {
|
||||
var currentElement = container;
|
||||
let currentElement = container;
|
||||
while (currentElement) {
|
||||
if (currentElement.className.includes(className)) {
|
||||
break;
|
||||
|
||||
50
src/sql/parts/objectExplorer/viewlet/treeNodeContextKey.ts
Normal file
50
src/sql/parts/objectExplorer/viewlet/treeNodeContextKey.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IConnectionProfile } from 'sqlops';
|
||||
import { TreeNode } from 'sql/parts/objectExplorer/common/treeNode';
|
||||
|
||||
export class TreeNodeContextKey implements IContextKey<TreeNode> {
|
||||
|
||||
static NodeType = new RawContextKey<string>('nodeType', undefined);
|
||||
static SubType = new RawContextKey<string>('nodeSubType', undefined);
|
||||
static Status = new RawContextKey<string>('nodeStatus', undefined);
|
||||
static TreeNode = new RawContextKey<TreeNode>('treeNode', undefined);
|
||||
|
||||
private _nodeTypeKey: IContextKey<string>;
|
||||
private _subTypeKey: IContextKey<string>;
|
||||
private _statusKey: IContextKey<string>;
|
||||
private _treeNodeKey: IContextKey<TreeNode>;
|
||||
|
||||
constructor(
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
this._nodeTypeKey = TreeNodeContextKey.NodeType.bindTo(contextKeyService);
|
||||
this._subTypeKey = TreeNodeContextKey.SubType.bindTo(contextKeyService);
|
||||
this._statusKey = TreeNodeContextKey.Status.bindTo(contextKeyService);
|
||||
this._treeNodeKey = TreeNodeContextKey.TreeNode.bindTo(contextKeyService);
|
||||
}
|
||||
|
||||
set(value: TreeNode) {
|
||||
this._treeNodeKey.set(value);
|
||||
this._nodeTypeKey.set(value && value.nodeTypeId);
|
||||
this._subTypeKey.set(value && value.nodeSubType);
|
||||
this._statusKey.set(value && value.nodeStatus);
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this._nodeTypeKey.reset();
|
||||
this._subTypeKey.reset();
|
||||
this._statusKey.reset();
|
||||
this._treeNodeKey.reset();
|
||||
}
|
||||
|
||||
public get(): TreeNode {
|
||||
return this._treeNodeKey.get();
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ export class TreeSelectionHandler {
|
||||
});
|
||||
}
|
||||
} else if (isDoubleClick && selection && selection.length > 0 && (selection[0] instanceof TreeNode)) {
|
||||
let treeNode = <TreeNode>selection[0];
|
||||
let treeNode = selection[0];
|
||||
if (TreeUpdateUtils.isAvailableDatabaseNode(treeNode)) {
|
||||
connectionProfile = TreeUpdateUtils.getConnectionProfile(treeNode);
|
||||
if (connectionProfile) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { NodeType } from 'sql/parts/objectExplorer/common/nodeType';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { TreeNode } from 'sql/parts/objectExplorer/common/treeNode';
|
||||
import errors = require('vs/base/common/errors');
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
|
||||
export class TreeUpdateUtils {
|
||||
|
||||
@@ -113,7 +114,7 @@ export class TreeUpdateUtils {
|
||||
}
|
||||
|
||||
public static connectIfNotConnected(
|
||||
connection: ConnectionProfile,
|
||||
connection: IConnectionProfile,
|
||||
options: IConnectionCompletionOptions,
|
||||
connectionManagementService: IConnectionManagementService,
|
||||
tree: ITree): TPromise<ConnectionProfile> {
|
||||
@@ -172,7 +173,7 @@ export class TreeUpdateUtils {
|
||||
* @param connectionManagementService Connection management service instance
|
||||
* @param objectExplorerService Object explorer service instance
|
||||
*/
|
||||
public static connectAndCreateOeSession(connection: ConnectionProfile, options: IConnectionCompletionOptions,
|
||||
public static connectAndCreateOeSession(connection: IConnectionProfile, options: IConnectionCompletionOptions,
|
||||
connectionManagementService: IConnectionManagementService, objectExplorerService: IObjectExplorerService, tree: ITree): TPromise<boolean> {
|
||||
return new TPromise<boolean>((resolve, reject) => {
|
||||
TreeUpdateUtils.connectIfNotConnected(connection, options, connectionManagementService, tree).then(connectedConnection => {
|
||||
|
||||
@@ -13,7 +13,7 @@ import * as nls from 'vs/nls';
|
||||
|
||||
import { ProfilerInput } from 'sql/parts/profiler/editor/profilerInput';
|
||||
import { ProfilerEditor } from 'sql/parts/profiler/editor/profilerEditor';
|
||||
import { PROFILER_SESSION_TEMPLATE_SETTINGS, IProfilerSessionTemplate } from 'sql/parts/profiler/service/interfaces';
|
||||
import { PROFILER_VIEW_TEMPLATE_SETTINGS, IProfilerViewTemplate } from 'sql/parts/profiler/service/interfaces';
|
||||
|
||||
const profilerDescriptor = new EditorDescriptor(
|
||||
ProfilerEditor,
|
||||
@@ -24,84 +24,213 @@ const profilerDescriptor = new EditorDescriptor(
|
||||
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
|
||||
.registerEditor(profilerDescriptor, [new SyncDescriptor(ProfilerInput)]);
|
||||
|
||||
const profilerSessionTemplateSchema: IJSONSchema = {
|
||||
description: nls.localize('profiler.settings.sessionTemplates', "Specifies session templates"),
|
||||
type: 'array',
|
||||
items: <IJSONSchema>{
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
default: <Array<IProfilerSessionTemplate>>[
|
||||
{
|
||||
name: 'Standard',
|
||||
events: [
|
||||
{
|
||||
name: 'Audit Login',
|
||||
optionalColumns: ['TextData', 'ApplicationName', 'NTUserName', 'LoginName', 'ClientProcessID', 'SPID', 'StartTime', 'BinaryData']
|
||||
},
|
||||
{
|
||||
name: 'Audit Logout',
|
||||
optionalColumns: ['ApplicationName', 'NTUserName', 'LoginName', 'CPU', 'Reads', 'Writes', 'Duration', 'ClientProcessID', 'SPID', 'StartTime', 'EndTime']
|
||||
},
|
||||
{
|
||||
name: 'ExistingConnection',
|
||||
optionalColumns: ['TextData', 'ApplicationName', 'NTUserName', 'LoginName', 'Duration', 'ClientProcessID', 'SPID', 'StartTime', 'EndTime', 'BinaryData']
|
||||
},
|
||||
{
|
||||
name: 'RPC:Completed',
|
||||
optionalColumns: ['TextData', 'ApplicationName', 'NTUserName', 'LoginName', 'CPU', 'Reads', 'Writes', 'Duration', 'ClientProcessID', 'SPID', 'StartTime', 'EndTime', 'BinaryData']
|
||||
},
|
||||
{
|
||||
name: 'SQL:BatchCompleted',
|
||||
optionalColumns: ['TextData', 'ApplicationName', 'NTUserName', 'LoginName', 'CPU', 'Reads', 'Writes', 'Duration', 'ClientProcessID', 'SPID', 'StartTime', 'EndTime', 'BinaryData']
|
||||
},
|
||||
{
|
||||
name: 'SQL:BatchStarting',
|
||||
optionalColumns: ['TextData', 'ApplicationName', 'NTUserName', 'LoginName', 'ClientProcessID', 'SPID', 'StartTime']
|
||||
const profilerViewTemplateSchema: IJSONSchema = {
|
||||
description: nls.localize('profiler.settings.viewTemplates', "Specifies view templates"),
|
||||
type: 'array',
|
||||
items: <IJSONSchema>{
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string'
|
||||
}
|
||||
],
|
||||
view: {
|
||||
events: [
|
||||
}
|
||||
},
|
||||
default: <Array<IProfilerViewTemplate>>[
|
||||
{
|
||||
name: 'Standard View',
|
||||
columns: [
|
||||
{
|
||||
name: 'Audit Login',
|
||||
columns: ['TextData', 'ApplicationName', 'NTUserName', 'LoginName', 'ClientProcessID', 'SPID', 'StartTime']
|
||||
name: 'EventClass',
|
||||
eventsMapped: ['name']
|
||||
},
|
||||
{
|
||||
name: 'Audit Logout',
|
||||
columns: ['ApplicationName', 'NTUserName', 'LoginName', 'CPU', 'Reads', 'Writes', 'Duration', 'ClientProcessID', 'SPID', 'StartTime', 'EndTime']
|
||||
name: 'TextData',
|
||||
eventsMapped: ['options_text', 'batch_text']
|
||||
},
|
||||
{
|
||||
name: 'ExistingConnection',
|
||||
columns: ['TextData', 'ApplicationName', 'NTUserName', 'LoginName', 'ClientProcessID', 'SPID', 'StartTime']
|
||||
name: 'ApplicationName',
|
||||
width: '1',
|
||||
eventsMapped: ['client_app_name']
|
||||
},
|
||||
{
|
||||
name: 'RPC:Completed',
|
||||
columns: ['ApplicationName', 'NTUserName', 'LoginName', 'CPU', 'Reads', 'Writes', 'Duration', 'ClientProcessID', 'SPID', 'StartTime', 'EndTime', 'BinaryData']
|
||||
name: 'NTUserName',
|
||||
eventsMapped: ['nt_username']
|
||||
},
|
||||
{
|
||||
name: 'SQL:BatchCompleted',
|
||||
columns: ['TextData', 'ApplicationName', 'NTUserName', 'LoginName', 'CPU', 'Reads', 'Writes', 'Duration', 'ClientProcessID', 'SPID', 'StartTime', 'EndTime', 'BinaryData']
|
||||
name: 'LoginName',
|
||||
eventsMapped: ['server_principal_name']
|
||||
},
|
||||
{
|
||||
name: 'SQL:BatchStarting',
|
||||
columns: ['TextData', 'ApplicationName', 'NTUserName', 'LoginName', 'ClientProcessID', 'SPID', 'StartTime']
|
||||
name: 'ClientProcessID',
|
||||
eventsMapped: ['client_pid']
|
||||
},
|
||||
{
|
||||
name: 'SPID',
|
||||
eventsMapped: ['session_id']
|
||||
},
|
||||
{
|
||||
name: 'StartTime',
|
||||
eventsMapped: ['timestamp']
|
||||
},
|
||||
{
|
||||
name: 'CPU',
|
||||
eventsMapped: ['cpu_time']
|
||||
},
|
||||
{
|
||||
name: 'Reads',
|
||||
eventsMapped: ['logical_reads']
|
||||
},
|
||||
{
|
||||
name: 'Writes',
|
||||
eventsMapped: ['writes']
|
||||
},
|
||||
{
|
||||
name: 'Duration',
|
||||
eventsMapped: ['duration']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'TSQL View',
|
||||
columns: [
|
||||
{
|
||||
name: 'EventClass',
|
||||
eventsMapped: ['name']
|
||||
},
|
||||
{
|
||||
name: 'TextData',
|
||||
eventsMapped: ['options_text', 'batch_text']
|
||||
},
|
||||
{
|
||||
name: 'SPID',
|
||||
eventsMapped: ['session_id']
|
||||
},
|
||||
{
|
||||
name: 'StartTime',
|
||||
eventsMapped: ['timestamp']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Tuning View',
|
||||
columns: [
|
||||
{
|
||||
name: 'EventClass',
|
||||
eventsMapped: ['name']
|
||||
},
|
||||
{
|
||||
name: 'TextData',
|
||||
eventsMapped: ['options_text', 'batch_text']
|
||||
},
|
||||
{
|
||||
name: 'Duration',
|
||||
eventsMapped: ['duration']
|
||||
},
|
||||
{
|
||||
name: 'SPID',
|
||||
eventsMapped: ['session_id']
|
||||
},
|
||||
{
|
||||
name: 'DatabaseID',
|
||||
eventsMapped: ['database_id']
|
||||
},
|
||||
{
|
||||
name: 'DatabaseName',
|
||||
eventsMapped: ['database_name']
|
||||
},
|
||||
{
|
||||
name: 'ObjectType',
|
||||
eventsMapped: ['object_type']
|
||||
},
|
||||
{
|
||||
name: 'LoginName',
|
||||
eventsMapped: ['server_principal_name']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'TSQL_Locks View',
|
||||
columns: [
|
||||
{
|
||||
name: 'EventClass',
|
||||
eventsMapped: ['name']
|
||||
},
|
||||
{
|
||||
name: 'TextData',
|
||||
eventsMapped: ['options_text', 'batch_text']
|
||||
},
|
||||
{
|
||||
name: 'ApplicationName',
|
||||
eventsMapped: ['client_app_name']
|
||||
},
|
||||
{
|
||||
name: 'NTUserName',
|
||||
eventsMapped: ['nt_username']
|
||||
},
|
||||
{
|
||||
name: 'LoginName',
|
||||
eventsMapped: ['server_principal_name']
|
||||
},
|
||||
{
|
||||
name: 'ClientProcessID',
|
||||
eventsMapped: ['client_pid']
|
||||
},
|
||||
{
|
||||
name: 'SPID',
|
||||
eventsMapped: ['session_id']
|
||||
},
|
||||
{
|
||||
name: 'StartTime',
|
||||
eventsMapped: ['timestamp']
|
||||
},
|
||||
{
|
||||
name: 'CPU',
|
||||
eventsMapped: ['cpu_time']
|
||||
},
|
||||
{
|
||||
name: 'Reads',
|
||||
eventsMapped: ['logical_reads']
|
||||
},
|
||||
{
|
||||
name: 'Writes',
|
||||
eventsMapped: ['writes']
|
||||
},
|
||||
{
|
||||
name: 'Duration',
|
||||
eventsMapped: ['duration']
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'TSQL_Duration View',
|
||||
columns: [
|
||||
{
|
||||
name: 'EventClass',
|
||||
eventsMapped: ['name']
|
||||
},
|
||||
{
|
||||
name: 'Duration',
|
||||
eventsMapped: ['duration']
|
||||
},
|
||||
{
|
||||
name: 'TextData',
|
||||
eventsMapped: ['options_text', 'batch_text']
|
||||
},
|
||||
{
|
||||
name: 'SPID',
|
||||
eventsMapped: ['session_id']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
]
|
||||
};
|
||||
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
||||
const dashboardConfig: IConfigurationNode = {
|
||||
id: 'Profiler',
|
||||
type: 'object',
|
||||
properties: {
|
||||
[PROFILER_SESSION_TEMPLATE_SETTINGS]: profilerSessionTemplateSchema
|
||||
[PROFILER_VIEW_TEMPLATE_SETTINGS]: profilerViewTemplateSchema
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -55,13 +55,17 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'profiler.newProfiler',
|
||||
weight: KeybindingsRegistry.WEIGHT.builtinExtension(),
|
||||
when: undefined,
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_P,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_P },
|
||||
primary: KeyMod.Alt | KeyCode.KEY_P,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KEY_P },
|
||||
handler: CommandsRegistry.getCommand('profiler.newProfiler').handler
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: 'profiler.start',
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'profiler.toggleStartStop',
|
||||
weight: KeybindingsRegistry.WEIGHT.editorContrib(),
|
||||
when: undefined,
|
||||
primary: KeyMod.Alt | KeyCode.KEY_S,
|
||||
mac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.KEY_S },
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
let profilerService: IProfilerService = accessor.get(IProfilerService);
|
||||
let editorService: IWorkbenchEditorService = accessor.get(IWorkbenchEditorService);
|
||||
@@ -69,23 +73,14 @@ CommandsRegistry.registerCommand({
|
||||
let activeEditor = editorService.getActiveEditor();
|
||||
if (activeEditor instanceof ProfilerEditor) {
|
||||
let profilerInput = activeEditor.input;
|
||||
return profilerService.startSession(profilerInput.id);
|
||||
if (profilerInput.state.isRunning){
|
||||
return profilerService.stopSession(profilerInput.id);
|
||||
} else {
|
||||
// clear data when profiler is started
|
||||
profilerInput.data.clear();
|
||||
return profilerService.startSession(profilerInput.id);
|
||||
}
|
||||
}
|
||||
return TPromise.as(false);
|
||||
}
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand({
|
||||
id: 'profiler.stop',
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
let profilerService: IProfilerService = accessor.get(IProfilerService);
|
||||
let editorService: IWorkbenchEditorService = accessor.get(IWorkbenchEditorService);
|
||||
|
||||
let activeEditor = editorService.getActiveEditor();
|
||||
if (activeEditor instanceof ProfilerEditor) {
|
||||
let profilerInput = activeEditor.input;
|
||||
return profilerService.stopSession(profilerInput.id);
|
||||
}
|
||||
return TPromise.as(false);
|
||||
}
|
||||
});
|
||||
@@ -360,7 +360,10 @@ export class ProfilerColumnEditorDialog extends Modal {
|
||||
super.onAccept(e);
|
||||
}
|
||||
|
||||
// currently not used, this dialog is a work in progress
|
||||
// tracked in issue #1545 https://github.com/Microsoft/sqlopsstudio/issues/1545
|
||||
private _updateInput(): void {
|
||||
/*
|
||||
this._element.getUnsortedChildren().forEach(e => {
|
||||
let origEvent = this._input.sessionTemplate.view.events.find(i => i.name === e.id);
|
||||
if (e.indeterminate) {
|
||||
@@ -387,9 +390,13 @@ export class ProfilerColumnEditorDialog extends Modal {
|
||||
}, []);
|
||||
newColumns.unshift('EventClass');
|
||||
this._input.setColumns(newColumns);
|
||||
*/
|
||||
}
|
||||
|
||||
// currently not used, this dialog is a work in progress
|
||||
// tracked in issue #1545 https://github.com/Microsoft/sqlopsstudio/issues/1545
|
||||
private _updateList(): void {
|
||||
/*
|
||||
this._element = new SessionItem(this._input.sessionTemplate.name, this._selectedValue === 0 ? 'event' : 'column');
|
||||
this._input.sessionTemplate.events.forEach(item => {
|
||||
let event = new EventItem(item.name, this._element);
|
||||
@@ -402,6 +409,7 @@ export class ProfilerColumnEditorDialog extends Modal {
|
||||
});
|
||||
this._tree.setInput(this._element);
|
||||
this._tree.layout(DOM.getTotalHeight(this._treeContainer));
|
||||
*/
|
||||
}
|
||||
|
||||
protected layout(height?: number): void {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { ProfilerInput } from './profilerInput';
|
||||
import { TabbedPanel } from 'sql/base/browser/ui/panel/panel';
|
||||
import { Table } from 'sql/base/browser/ui/table/table';
|
||||
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
|
||||
import { IProfilerService, IProfilerSessionTemplate } from 'sql/parts/profiler/service/interfaces';
|
||||
import { IProfilerService, IProfilerViewTemplate } from 'sql/parts/profiler/service/interfaces';
|
||||
import { Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||
import { attachTableStyler } from 'sql/common/theme/styler';
|
||||
import { IProfilerStateChangedEvent } from './profilerState';
|
||||
@@ -114,8 +114,8 @@ export class ProfilerEditor extends BaseEditor {
|
||||
|
||||
private _profilerEditorContextKey: IContextKey<boolean>;
|
||||
|
||||
private _sessionTemplateSelector: SelectBox;
|
||||
private _sessionTemplates: Array<IProfilerSessionTemplate>;
|
||||
private _viewTemplateSelector: SelectBox;
|
||||
private _viewTemplates: Array<IProfilerViewTemplate>;
|
||||
|
||||
// Actions
|
||||
private _connectAction: Actions.ProfilerConnect;
|
||||
@@ -125,6 +125,7 @@ export class ProfilerEditor extends BaseEditor {
|
||||
private _autoscrollAction: Actions.ProfilerAutoScroll;
|
||||
private _collapsedPanelAction: Actions.ProfilerCollapsablePanelAction;
|
||||
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IWorkbenchThemeService themeService: IWorkbenchThemeService,
|
||||
@@ -189,27 +190,27 @@ export class ProfilerEditor extends BaseEditor {
|
||||
this._connectAction = this._instantiationService.createInstance(Actions.ProfilerConnect, Actions.ProfilerConnect.ID, Actions.ProfilerConnect.LABEL);
|
||||
this._autoscrollAction = this._instantiationService.createInstance(Actions.ProfilerAutoScroll, Actions.ProfilerAutoScroll.ID, Actions.ProfilerAutoScroll.LABEL);
|
||||
|
||||
this._sessionTemplates = this._profilerService.getSessionTemplates();
|
||||
this._sessionTemplateSelector = new SelectBox(this._sessionTemplates.map(i => i.name), 'Standard', this._contextViewService);
|
||||
this._register(this._sessionTemplateSelector.onDidSelect(e => {
|
||||
this._viewTemplates = this._profilerService.getViewTemplates();
|
||||
this._viewTemplateSelector = new SelectBox(this._viewTemplates.map(i => i.name), 'Standard View', this._contextViewService);
|
||||
this._register(this._viewTemplateSelector.onDidSelect(e => {
|
||||
if (this.input) {
|
||||
this.input.sessionTemplate = this._sessionTemplates.find(i => i.name === e.selected);
|
||||
this.input.viewTemplate = this._viewTemplates.find(i => i.name === e.selected);
|
||||
}
|
||||
}));
|
||||
let dropdownContainer = document.createElement('div');
|
||||
dropdownContainer.style.width = '150px';
|
||||
this._sessionTemplateSelector.render(dropdownContainer);
|
||||
this._viewTemplateSelector.render(dropdownContainer);
|
||||
|
||||
this._register(attachSelectBoxStyler(this._sessionTemplateSelector, this.themeService));
|
||||
this._register(attachSelectBoxStyler(this._viewTemplateSelector, this.themeService));
|
||||
|
||||
this._actionBar.setContent([
|
||||
{ action: this._startAction },
|
||||
{ action: this._stopAction },
|
||||
{ element: dropdownContainer },
|
||||
{ element: Taskbar.createTaskbarSeparator() },
|
||||
{ action: this._pauseAction },
|
||||
{ action: this._autoscrollAction },
|
||||
{ action: this._instantiationService.createInstance(Actions.ProfilerClear, Actions.ProfilerClear.ID, Actions.ProfilerClear.LABEL) }
|
||||
{ action: this._instantiationService.createInstance(Actions.ProfilerClear, Actions.ProfilerClear.ID, Actions.ProfilerClear.LABEL) },
|
||||
{ element: dropdownContainer },
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -340,10 +341,10 @@ export class ProfilerEditor extends BaseEditor {
|
||||
return super.setInput(input, options).then(() => {
|
||||
this._profilerTableEditor.setInput(input);
|
||||
|
||||
if (input.sessionTemplate) {
|
||||
this._sessionTemplateSelector.selectWithOptionName(input.sessionTemplate.name);
|
||||
if (input.viewTemplate) {
|
||||
this._viewTemplateSelector.selectWithOptionName(input.viewTemplate.name);
|
||||
} else {
|
||||
input.sessionTemplate = this._sessionTemplates.find(i => i.name === 'Standard');
|
||||
input.viewTemplate = this._viewTemplates.find(i => i.name === 'Standard View');
|
||||
}
|
||||
|
||||
this._actionBar.context = input;
|
||||
@@ -401,10 +402,7 @@ export class ProfilerEditor extends BaseEditor {
|
||||
|
||||
if (e.isConnected) {
|
||||
this._connectAction.connected = this.input.state.isConnected;
|
||||
if (this.input.state.isConnected) {
|
||||
this._sessionTemplateSelector.disable();
|
||||
} else {
|
||||
this._sessionTemplateSelector.enable();
|
||||
if (!this.input.state.isConnected) {
|
||||
this._startAction.enabled = this.input.state.isConnected;
|
||||
this._stopAction.enabled = false;
|
||||
this._pauseAction.enabled = false;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
|
||||
import { IProfilerSession, IProfilerService, ProfilerSessionID, IProfilerSessionTemplate } from 'sql/parts/profiler/service/interfaces';
|
||||
import { IProfilerSession, IProfilerService, ProfilerSessionID, IProfilerViewTemplate } from 'sql/parts/profiler/service/interfaces';
|
||||
import { ProfilerState } from './profilerState';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
|
||||
@@ -28,7 +28,10 @@ export class ProfilerInput extends EditorInput implements IProfilerSession {
|
||||
private _id: ProfilerSessionID;
|
||||
private _state: ProfilerState;
|
||||
private _columns: string[] = [];
|
||||
private _sessionTemplate: IProfilerSessionTemplate;
|
||||
private _viewTemplate: IProfilerViewTemplate;
|
||||
// mapping of event categories to what column they display under
|
||||
// used for coallescing multiple events with different names to the same column
|
||||
private _columnMapping: { [event: string]: string } = {};
|
||||
|
||||
private _onColumnsChanged = new Emitter<Slick.Column<Slick.SlickData>[]>();
|
||||
public onColumnsChanged: Event<Slick.Column<Slick.SlickData>[]> = this._onColumnsChanged.event;
|
||||
@@ -63,22 +66,26 @@ export class ProfilerInput extends EditorInput implements IProfilerSession {
|
||||
this._data = new TableDataView<Slick.SlickData>(undefined, searchFn);
|
||||
}
|
||||
|
||||
public set sessionTemplate(template: IProfilerSessionTemplate) {
|
||||
this._sessionTemplate = template;
|
||||
let newColumns = this.sessionTemplate.view.events.reduce<Array<string>>((p, e) => {
|
||||
e.columns.forEach(c => {
|
||||
if (!p.includes(c)) {
|
||||
p.push(c);
|
||||
}
|
||||
});
|
||||
public set viewTemplate(template: IProfilerViewTemplate) {
|
||||
this._data.clear();
|
||||
this._viewTemplate = template;
|
||||
|
||||
let newColumns = this._viewTemplate.columns.reduce<Array<string>>((p, e) => {
|
||||
p.push(e.name);
|
||||
return p;
|
||||
}, []);
|
||||
newColumns.unshift('EventClass');
|
||||
this.setColumns(newColumns);
|
||||
|
||||
let newMapping: { [event: string]: string } = {};
|
||||
this._viewTemplate.columns.forEach(c => {
|
||||
c.eventsMapped.forEach(e => {
|
||||
newMapping[e] = c.name;
|
||||
});
|
||||
});
|
||||
this.setColumnMapping(newColumns, newMapping);
|
||||
}
|
||||
|
||||
public get sessionTemplate(): IProfilerSessionTemplate {
|
||||
return this._sessionTemplate;
|
||||
public get viewTemplate(): IProfilerViewTemplate {
|
||||
return this._viewTemplate;
|
||||
}
|
||||
|
||||
public getTypeId(): string {
|
||||
@@ -117,6 +124,12 @@ export class ProfilerInput extends EditorInput implements IProfilerSession {
|
||||
this._onColumnsChanged.fire(this.columns);
|
||||
}
|
||||
|
||||
public setColumnMapping(columns: Array<string>, mapping: { [event: string]: string }) {
|
||||
this._columns = columns;
|
||||
this._columnMapping = mapping;
|
||||
this._onColumnsChanged.fire(this.columns);
|
||||
}
|
||||
|
||||
public get id(): ProfilerSessionID {
|
||||
return this._id;
|
||||
}
|
||||
@@ -140,51 +153,22 @@ export class ProfilerInput extends EditorInput implements IProfilerSession {
|
||||
}
|
||||
|
||||
public onMoreRows(eventMessage: sqlops.ProfilerSessionEvents) {
|
||||
if (eventMessage.eventsLost){
|
||||
if (eventMessage.eventsLost) {
|
||||
this._notificationService.warn(nls.localize("profiler.eventsLost", "The XEvent Profiler session for {0} has lost events.", this._connection.serverName));
|
||||
}
|
||||
|
||||
for (let i: number = 0; i < eventMessage.events.length && i < 500; ++i) {
|
||||
for (let i: number = 0; i < eventMessage.events.length && i < 500; ++i) {
|
||||
let e: sqlops.ProfilerEvent = eventMessage.events[i];
|
||||
let data = {};
|
||||
data['EventClass'] = e.name;
|
||||
data['EventClass'] = e.name;
|
||||
data['StartTime'] = e.timestamp;
|
||||
const columns = [
|
||||
'TextData',
|
||||
'ApplicationName',
|
||||
'NTUserName',
|
||||
'LoginName',
|
||||
'CPU',
|
||||
'Reads',
|
||||
'Writes',
|
||||
'Duration',
|
||||
'ClientProcessID',
|
||||
'SPID',
|
||||
'StartTime',
|
||||
'EndTime',
|
||||
'BinaryData'
|
||||
];
|
||||
|
||||
let columnNameMap: Map<string, string> = new Map<string, string>();
|
||||
columnNameMap['client_app_name'] = 'ApplicationName';
|
||||
columnNameMap['nt_username'] = 'NTUserName';
|
||||
columnNameMap['options_text'] = 'TextData';
|
||||
columnNameMap['server_principal_name'] = 'LoginName';
|
||||
columnNameMap['session_id'] = 'SPID';
|
||||
columnNameMap['batch_text'] = 'TextData';
|
||||
columnNameMap['cpu_time'] = 'CPU';
|
||||
columnNameMap['duration'] = 'Duration';
|
||||
columnNameMap['logical_reads'] = 'Reads';
|
||||
columnNameMap['event_sequence'] = 'EventSequence';
|
||||
columnNameMap['client_pid'] = 'ClientProcessID';
|
||||
columnNameMap['writes'] = 'Writes';
|
||||
|
||||
// Using ' ' instead of '' fixed the error where clicking through events
|
||||
// with empty text fields causes future text panes to be highlighted.
|
||||
// This is a temporary fix, and should be changed before the July release
|
||||
// This is a temporary fix
|
||||
data['TextData'] = ' ';
|
||||
for (let key in e.values) {
|
||||
let columnName = columnNameMap[key];
|
||||
let columnName = this._columnMapping[key];
|
||||
if (columnName) {
|
||||
let value = e.values[key];
|
||||
data[columnName] = value;
|
||||
|
||||
@@ -15,7 +15,7 @@ export const IProfilerService = createDecorator<IProfilerService>(PROFILER_SERVI
|
||||
|
||||
export type ProfilerSessionID = string;
|
||||
|
||||
export const PROFILER_SESSION_TEMPLATE_SETTINGS = 'profiler.sessionTemplates';
|
||||
export const PROFILER_VIEW_TEMPLATE_SETTINGS = 'profiler.viewTemplates';
|
||||
export const PROFILER_SETTINGS = 'profiler';
|
||||
|
||||
/**
|
||||
@@ -84,7 +84,7 @@ export interface IProfilerService {
|
||||
* @returns An array of session templates that match the provider passed, if passed, and generic ones (no provider specified),
|
||||
* otherwise returns all session templates
|
||||
*/
|
||||
getSessionTemplates(providerId?: string): Array<IProfilerSessionTemplate>;
|
||||
getViewTemplates(providerId?: string): Array<IProfilerViewTemplate>;
|
||||
/**
|
||||
* Launches the dialog for editing the view columns of a profiler session template for the given input
|
||||
* @param input input object that contains the necessary information which will be modified based on used input
|
||||
@@ -93,25 +93,16 @@ export interface IProfilerService {
|
||||
}
|
||||
|
||||
export interface IProfilerSettings {
|
||||
sessionTemplates: Array<IProfilerSessionTemplate>;
|
||||
viewTemplates: Array<IProfilerViewTemplate>;
|
||||
}
|
||||
|
||||
export interface IEventTemplate {
|
||||
export interface IColumnViewTemplate {
|
||||
name: string;
|
||||
optionalColumns: Array<string>;
|
||||
width: string;
|
||||
eventsMapped: Array<string>;
|
||||
}
|
||||
|
||||
export interface IEventViewTemplate {
|
||||
export interface IProfilerViewTemplate {
|
||||
name: string;
|
||||
columns: Array<string>;
|
||||
}
|
||||
|
||||
export interface ISessionViewTemplate {
|
||||
events: Array<IEventViewTemplate>;
|
||||
}
|
||||
|
||||
export interface IProfilerSessionTemplate {
|
||||
name: string;
|
||||
events: Array<IEventTemplate>;
|
||||
view: ISessionViewTemplate;
|
||||
columns: Array<IColumnViewTemplate>;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { IConnectionManagementService, IConnectionCompletionOptions, ConnectionType, RunQueryOnConnectionMode } from 'sql/parts/connection/common/connectionManagement';
|
||||
import {
|
||||
ProfilerSessionID, IProfilerSession, IProfilerService, IProfilerSessionTemplate,
|
||||
ProfilerSessionID, IProfilerSession, IProfilerService, IProfilerViewTemplate,
|
||||
PROFILER_SETTINGS, IProfilerSettings
|
||||
} from './interfaces';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
@@ -128,13 +128,13 @@ export class ProfilerService implements IProfilerService {
|
||||
}
|
||||
}
|
||||
|
||||
public getSessionTemplates(provider?: string): Array<IProfilerSessionTemplate> {
|
||||
public getViewTemplates(provider?: string): Array<IProfilerViewTemplate> {
|
||||
let config = <IProfilerSettings>this._configurationService.getValue(PROFILER_SETTINGS);
|
||||
|
||||
if (provider) {
|
||||
return config.sessionTemplates;
|
||||
return config.viewTemplates;
|
||||
} else {
|
||||
return config.sessionTemplates;
|
||||
return config.viewTemplates;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -275,6 +275,11 @@ let registryProperties = {
|
||||
'description': localize('sql.saveAsCsv.includeHeaders', '[Optional] When true, column headers are included when saving results as CSV'),
|
||||
'default': true
|
||||
},
|
||||
'sql.saveAsCsv.delimiter': {
|
||||
'type': 'string',
|
||||
'description': localize('sql.saveAsCsv.delimiter', '[Optional] The custom delimiter to use between values when saving as CSV'),
|
||||
'default': ','
|
||||
},
|
||||
'sql.copyIncludeHeaders': {
|
||||
'type': 'boolean',
|
||||
'description': localize('sql.copyIncludeHeaders', '[Optional] Configuration options for copying results from the Results View'),
|
||||
|
||||
@@ -21,6 +21,7 @@ export interface IQueryManagementService {
|
||||
_serviceBrand: any;
|
||||
|
||||
addQueryRequestHandler(queryType: string, runner: IQueryRequestHandler): IDisposable;
|
||||
isProviderRegistered(providerId: string): boolean;
|
||||
registerRunner(runner: QueryRunner, uri: string): void;
|
||||
|
||||
cancelQuery(ownerUri: string): Thenable<sqlops.QueryCancelResult>;
|
||||
@@ -82,7 +83,6 @@ export interface IQueryRequestHandler {
|
||||
}
|
||||
|
||||
export class QueryManagementService implements IQueryManagementService {
|
||||
public static readonly DefaultQueryType = 'MSSQL';
|
||||
public _serviceBrand: any;
|
||||
|
||||
private _requestHandlers = new Map<string, IQueryRequestHandler>();
|
||||
@@ -143,6 +143,11 @@ export class QueryManagementService implements IQueryManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
public isProviderRegistered(providerId: string): boolean {
|
||||
let handler = this._requestHandlers.get(providerId);
|
||||
return !!handler;
|
||||
}
|
||||
|
||||
private addTelemetry(eventName: string, ownerUri: string, runOptions?: sqlops.ExecutionPlanOptions): void {
|
||||
let providerId: string = this._connectionService.getProviderIdFromUri(ownerUri);
|
||||
let data: TelemetryUtils.IConnectionTelemetryData = {
|
||||
|
||||
@@ -186,7 +186,11 @@ export class ResultSerializer {
|
||||
if (saveConfig.includeHeaders !== undefined) {
|
||||
saveResultsParams.includeHeaders = saveConfig.includeHeaders;
|
||||
}
|
||||
if (saveConfig.delimiter !== undefined) {
|
||||
saveResultsParams.delimiter = saveConfig.delimiter;
|
||||
}
|
||||
}
|
||||
|
||||
return saveResultsParams;
|
||||
}
|
||||
|
||||
@@ -202,6 +206,7 @@ export class ResultSerializer {
|
||||
// and we want to have just 1 setting that lists this.
|
||||
let config = this.getConfigForCsv();
|
||||
config.resultFormat = SaveFormat.EXCEL;
|
||||
config.delimiter = undefined;
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import { CommonModule, APP_BASE_HREF } from '@angular/common';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { DialogContainer } from 'sql/platform/dialog/dialogContainer.component';
|
||||
import { WizardNavigation } from 'sql/platform/dialog/wizardNavigation.component';
|
||||
import { Extensions, IComponentRegistry } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
||||
import { ModelViewContent } from 'sql/parts/modelComponents/modelViewContent.component';
|
||||
import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component';
|
||||
@@ -37,12 +38,13 @@ export const DialogModule = (params, selector: string, instantiationService: IIn
|
||||
SelectBox,
|
||||
InputBox,
|
||||
DialogContainer,
|
||||
WizardNavigation,
|
||||
ModelViewContent,
|
||||
ModelComponentWrapper,
|
||||
ComponentHostDirective,
|
||||
...extensionComponents
|
||||
],
|
||||
entryComponents: [DialogContainer, ...extensionComponents],
|
||||
entryComponents: [DialogContainer, WizardNavigation, ...extensionComponents],
|
||||
imports: [
|
||||
FormsModule,
|
||||
CommonModule,
|
||||
@@ -65,7 +67,8 @@ export const DialogModule = (params, selector: string, instantiationService: IIn
|
||||
}
|
||||
|
||||
ngDoBootstrap(appRef: ApplicationRef) {
|
||||
const factoryWrapper: any = this._resolver.resolveComponentFactory(DialogContainer);
|
||||
let componentClass = this.selector.startsWith(WizardNavigation.SELECTOR) ? WizardNavigation : DialogContainer;
|
||||
const factoryWrapper: any = this._resolver.resolveComponentFactory<WizardNavigation | DialogContainer>(componentClass);
|
||||
factoryWrapper.factory.selector = this.selector;
|
||||
appRef.bootstrap(factoryWrapper);
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ export class DialogModal extends Modal {
|
||||
}
|
||||
|
||||
public async done(): Promise<void> {
|
||||
if (this._dialog.okButton.enabled) {
|
||||
if (this._doneButton.enabled) {
|
||||
if (await this._dialog.validateClose()) {
|
||||
this._onDone.fire();
|
||||
this.dispose();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
.dialogModal-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
min-width: 500px;
|
||||
|
||||
94
src/sql/platform/dialog/media/wizardNavigation.css
Normal file
94
src/sql/platform/dialog/media/wizardNavigation.css
Normal file
@@ -0,0 +1,94 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.wizardNavigation-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 80px;
|
||||
height: calc(100% + 25px);
|
||||
margin-top: -25px;
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-container {
|
||||
border-right-color: #2b56f2;
|
||||
border-right-style: solid;
|
||||
border-right-width: 1px;
|
||||
background-color: unset;
|
||||
}
|
||||
|
||||
.wizardNavigation-pageNumber {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-height: 130px;
|
||||
}
|
||||
|
||||
.wizardNavigation-pageNumber a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.wizardNavigation-dot {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
background-color: rgb(200, 200, 200);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
border-style: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-dot {
|
||||
flex-grow: 1;
|
||||
background-color: unset;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
.wizardNavigation-connector {
|
||||
width: 3px;
|
||||
display: inline-block;
|
||||
flex-grow: 1;
|
||||
background-color: rgb(200, 200, 200);
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-connector {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wizardNavigation-connector.active,
|
||||
.wizardNavigation-dot.active {
|
||||
background-color: rgb(9, 109, 201);
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-dot.active {
|
||||
border-color: #2b56f2;
|
||||
background-color: unset;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-dot.active:hover,
|
||||
.hc-black .wizardNavigation-dot.active.currentPage:hover {
|
||||
border-color: #F38518;
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.wizardNavigation-dot.active.currentPage {
|
||||
border-style: double;
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-dot.active.currentPage {
|
||||
border-style: solid;
|
||||
border-color: #F38518;
|
||||
}
|
||||
|
||||
.wizardNavigation-connector.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
@@ -8,23 +8,22 @@
|
||||
import 'vs/css!./media/dialogModal';
|
||||
import { Modal, IModalOptions } from 'sql/base/browser/ui/modal/modal';
|
||||
import { attachModalDialogStyler } from 'sql/common/theme/styler';
|
||||
import { Wizard, Dialog, DialogButton, WizardPage } from 'sql/platform/dialog/dialogTypes';
|
||||
import { Wizard, DialogButton, WizardPage } from 'sql/platform/dialog/dialogTypes';
|
||||
import { DialogPane } from 'sql/platform/dialog/dialogPane';
|
||||
import { bootstrapAngular } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { DialogMessage } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { DialogModule } from 'sql/platform/dialog/dialog.module';
|
||||
import { Button } from 'vs/base/browser/ui/button/button';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { Builder } from 'vs/base/browser/builder';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
|
||||
import { localize } from 'vs/nls';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { DialogMessage, MessageLevel } from '../../workbench/api/common/sqlExtHostTypes';
|
||||
|
||||
export class WizardModal extends Modal {
|
||||
private _dialogPanes = new Map<WizardPage, DialogPane>();
|
||||
@@ -128,6 +127,8 @@ export class WizardModal extends Modal {
|
||||
this._body = bodyBuilder.getHTMLElement();
|
||||
});
|
||||
|
||||
this.initializeNavigation(this._body);
|
||||
|
||||
this._wizard.pages.forEach(page => {
|
||||
this.registerPage(page);
|
||||
});
|
||||
@@ -201,13 +202,29 @@ export class WizardModal extends Modal {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap angular for the wizard's left nav bar
|
||||
*/
|
||||
private initializeNavigation(bodyContainer: HTMLElement) {
|
||||
bootstrapAngular(this._instantiationService,
|
||||
DialogModule,
|
||||
bodyContainer,
|
||||
'wizard-navigation',
|
||||
{
|
||||
wizard: this._wizard,
|
||||
navigationHandler: (index: number) => this.showPage(index, index > this._wizard.currentPage)
|
||||
},
|
||||
undefined,
|
||||
() => undefined);
|
||||
}
|
||||
|
||||
public open(): void {
|
||||
this.showPage(0, false);
|
||||
this.show();
|
||||
}
|
||||
|
||||
public async done(validate: boolean = true): Promise<void> {
|
||||
if (this._wizard.doneButton.enabled) {
|
||||
if (this._doneButton.enabled) {
|
||||
if (validate && !await this._wizard.validateNavigation(undefined)) {
|
||||
return;
|
||||
}
|
||||
@@ -242,7 +259,13 @@ export class WizardModal extends Modal {
|
||||
* Overridable to change behavior of enter key
|
||||
*/
|
||||
protected onAccept(e: StandardKeyboardEvent) {
|
||||
this.done();
|
||||
if (this._wizard.currentPage === this._wizard.pages.length - 1) {
|
||||
this.done();
|
||||
} else {
|
||||
if (this._nextButton.enabled) {
|
||||
this.showPage(this._wizard.currentPage + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
||||
91
src/sql/platform/dialog/wizardNavigation.component.ts
Normal file
91
src/sql/platform/dialog/wizardNavigation.component.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 'vs/css!./media/wizardNavigation';
|
||||
import { Component, Inject, forwardRef, ElementRef, AfterViewInit, ChangeDetectorRef, ViewChild } from '@angular/core';
|
||||
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Wizard } from './dialogTypes';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { attachStyler } from 'vs/platform/theme/common/styler';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
|
||||
export class WizardNavigationParams implements IBootstrapParams {
|
||||
wizard: Wizard;
|
||||
navigationHandler: (index: number) => void;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: WizardNavigation.SELECTOR,
|
||||
providers: [],
|
||||
template: `
|
||||
<div #container class="wizardNavigation-container">
|
||||
<ng-container *ngFor="let item of _params.wizard.pages; let i = index">
|
||||
<div class="wizardNavigation-pageNumber">
|
||||
<div class="wizardNavigation-connector" [ngClass]="{'invisible': !hasTopConnector(i), 'active': isActive(i)}"></div>
|
||||
<a [attr.href]="isActive(i) ? '' : null" [title]="item.title">
|
||||
<span class="wizardNavigation-dot" [ngClass]="{'active': isActive(i), 'currentPage': isCurrentPage(i)}" (click)="navigate(i)">{{i+1}}</span>
|
||||
</a>
|
||||
<div class="wizardNavigation-connector" [ngClass]="{'invisible': !hasBottomConnector(i), 'active': isActive(i)}"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class WizardNavigation implements AfterViewInit {
|
||||
public static readonly SELECTOR = 'wizard-navigation';
|
||||
|
||||
private _onResize = new Emitter<void>();
|
||||
public readonly onResize: Event<void> = this._onResize.event;
|
||||
|
||||
@ViewChild('container', { read: ElementRef }) private _container: ElementRef;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(IBootstrapParams) private _params: WizardNavigationParams,
|
||||
@Inject(IWorkbenchThemeService) private _themeService: IWorkbenchThemeService) {
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this._themeService.onThemeChange(() => this.style());
|
||||
this.style();
|
||||
this._params.wizard.onPageChanged(() => this._changeRef.detectChanges());
|
||||
}
|
||||
|
||||
hasTopConnector(index: number): boolean {
|
||||
return index > 0;
|
||||
}
|
||||
|
||||
hasBottomConnector(index: number): boolean {
|
||||
return index + 1 !== this._params.wizard.pages.length;
|
||||
}
|
||||
|
||||
isActive(index: number): boolean {
|
||||
return index <= this._params.wizard.currentPage;
|
||||
}
|
||||
|
||||
isCurrentPage(index: number): boolean {
|
||||
return index === this._params.wizard.currentPage;
|
||||
}
|
||||
|
||||
navigate(index: number): void {
|
||||
if (this.isActive(index)) {
|
||||
this._params.navigationHandler(index);
|
||||
}
|
||||
}
|
||||
|
||||
private style(): void {
|
||||
let theme = this._themeService.getTheme();
|
||||
let navigationBackgroundColor = theme.getColor(SIDE_BAR_BACKGROUND);
|
||||
if (theme.type === 'light') {
|
||||
navigationBackgroundColor = navigationBackgroundColor.lighten(0.03);
|
||||
} else if (theme.type === 'dark') {
|
||||
navigationBackgroundColor = navigationBackgroundColor.darken(0.03);
|
||||
}
|
||||
(this._container.nativeElement as HTMLElement).style.backgroundColor = navigationBackgroundColor.toString();
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
import { DataService } from 'sql/parts/grid/services/dataService';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ConnectionContextkey } from 'sql/parts/connection/common/connectionContextKey';
|
||||
import { ConnectionContextKey } from 'sql/parts/connection/common/connectionContextKey';
|
||||
import { IBootstrapParams } from './bootstrapService';
|
||||
|
||||
export interface IQueryComponentParams extends IBootstrapParams {
|
||||
@@ -21,7 +21,7 @@ export interface IDefaultComponentParams extends IBootstrapParams {
|
||||
connection: IConnectionProfile;
|
||||
ownerUri: string;
|
||||
scopedContextService: IContextKeyService;
|
||||
connectionContextKey: ConnectionContextkey;
|
||||
connectionContextKey: ConnectionContextKey;
|
||||
}
|
||||
|
||||
export interface IDashboardComponentParams extends IDefaultComponentParams {
|
||||
|
||||
@@ -17,7 +17,7 @@ import { IAdminService } from 'sql/parts/admin/common/adminService';
|
||||
import { IQueryManagementService } from 'sql/parts/query/common/queryManagement';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||
import { ConnectionContextkey } from 'sql/parts/connection/common/connectionContextKey';
|
||||
import { ConnectionContextKey } from 'sql/parts/connection/common/connectionContextKey';
|
||||
|
||||
import { ProviderMetadata, DatabaseInfo, SimpleExecuteResult } from 'sqlops';
|
||||
|
||||
@@ -47,7 +47,7 @@ export class SingleConnectionManagementService {
|
||||
constructor(
|
||||
private _connectionService: IConnectionManagementService,
|
||||
private _uri: string,
|
||||
private _contextKey: ConnectionContextkey
|
||||
private _contextKey: ConnectionContextKey
|
||||
) { }
|
||||
|
||||
public changeDatabase(name: string): Thenable<boolean> {
|
||||
@@ -104,7 +104,7 @@ export class CommonServiceInterface extends AngularDisposable {
|
||||
protected _singleQueryManagementService: SingleQueryManagementService;
|
||||
public scopedContextKeyService: IContextKeyService;
|
||||
|
||||
protected _connectionContextKey: ConnectionContextkey;
|
||||
protected _connectionContextKey: ConnectionContextKey;
|
||||
|
||||
constructor(
|
||||
@Inject(IBootstrapParams) protected _params: IDefaultComponentParams,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
export const IDashboardService = createDecorator<IDashboardService>('dashboardService');
|
||||
@@ -16,8 +16,11 @@ export interface IDashboardService {
|
||||
_serviceBrand: any;
|
||||
readonly onDidOpenDashboard: Event<sqlops.DashboardDocument>;
|
||||
readonly onDidChangeToDashboard: Event<sqlops.DashboardDocument>;
|
||||
readonly onLayout: Event<DOM.Dimension>;
|
||||
|
||||
openDashboard(document: sqlops.DashboardDocument): void;
|
||||
|
||||
changeToDashboard(document: sqlops.DashboardDocument): void;
|
||||
|
||||
layout(dimension: DOM.Dimension): void;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
'use strict';
|
||||
|
||||
import { IDashboardService } from './dashboardService';
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as sqlops from 'sqlops';
|
||||
|
||||
export class DashboardService implements IDashboardService {
|
||||
@@ -18,6 +17,9 @@ export class DashboardService implements IDashboardService {
|
||||
private _onDidChangeToDashboard = new Emitter<sqlops.DashboardDocument>();
|
||||
public readonly onDidChangeToDashboard: Event<sqlops.DashboardDocument> = this._onDidChangeToDashboard.event;
|
||||
|
||||
private _onLayout = new Emitter<DOM.Dimension>();
|
||||
public readonly onLayout: Event<DOM.Dimension> = this._onLayout.event;
|
||||
|
||||
public openDashboard(document: sqlops.DashboardDocument): void {
|
||||
this._onDidOpenDashboard.fire(document);
|
||||
}
|
||||
@@ -25,4 +27,8 @@ export class DashboardService implements IDashboardService {
|
||||
public changeToDashboard(document: sqlops.DashboardDocument): void {
|
||||
this._onDidChangeToDashboard.fire(document);
|
||||
}
|
||||
|
||||
public layout(dimension: DOM.Dimension): void {
|
||||
this._onLayout.fire(dimension);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ export interface IScriptingService {
|
||||
*/
|
||||
registerProvider(providerId: string, provider: sqlops.ScriptingProvider): void;
|
||||
|
||||
/**
|
||||
* Specifies whether a provider with a given ID has been registered or not
|
||||
*/
|
||||
isProviderRegistered(providerId: string): boolean;
|
||||
|
||||
/**
|
||||
* Callback method for when scripting is complete
|
||||
*/
|
||||
@@ -99,6 +104,11 @@ export class ScriptingService implements IScriptingService {
|
||||
this._providers[providerId] = provider;
|
||||
}
|
||||
|
||||
public isProviderRegistered(providerId: string): boolean {
|
||||
let provider = this._providers[providerId];
|
||||
return !!provider;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
|
||||
144
src/sql/sqlops.d.ts
vendored
144
src/sql/sqlops.d.ts
vendored
@@ -770,6 +770,11 @@ declare module 'sqlops' {
|
||||
rows: DbCellValue[][];
|
||||
}
|
||||
|
||||
export interface SyntaxParseParams {
|
||||
ownerUri: string;
|
||||
query: string;
|
||||
}
|
||||
|
||||
export interface SyntaxParseResult {
|
||||
parseable: boolean;
|
||||
errorMessages: string[];
|
||||
@@ -835,6 +840,7 @@ declare module 'sqlops' {
|
||||
columnStartIndex: number;
|
||||
columnEndIndex: number;
|
||||
includeHeaders?: boolean;
|
||||
delimiter?: string;
|
||||
}
|
||||
|
||||
export interface SaveResultRequestResult {
|
||||
@@ -928,6 +934,10 @@ declare module 'sqlops' {
|
||||
subset: EditRow[];
|
||||
}
|
||||
|
||||
/**
|
||||
* A NodeInfo object represents an element in the Object Explorer tree under
|
||||
* a connection.
|
||||
*/
|
||||
export interface NodeInfo {
|
||||
nodePath: string;
|
||||
nodeType: string;
|
||||
@@ -937,6 +947,116 @@ declare module 'sqlops' {
|
||||
isLeaf: boolean;
|
||||
metadata: ObjectMetadata;
|
||||
errorMessage: string;
|
||||
/**
|
||||
* Optional iconType for the object in the tree. Currently this only supports
|
||||
* an icon name or SqlThemeIcon name, rather than a path to an icon.
|
||||
* If not defined, the nodeType + nodeStatus / nodeSubType values
|
||||
* will be used instead.
|
||||
*/
|
||||
iconType?: string | SqlThemeIcon;
|
||||
}
|
||||
|
||||
/**
|
||||
* A reference to a named icon. Currently only a subset of the SQL icons are available.
|
||||
* Using a theme icon is preferred over a custom icon as it gives theme authors the possibility to change the icons.
|
||||
*/
|
||||
export class SqlThemeIcon {
|
||||
static readonly Folder: SqlThemeIcon;
|
||||
static readonly Root: SqlThemeIcon;
|
||||
static readonly Database: SqlThemeIcon;
|
||||
static readonly Server: SqlThemeIcon;
|
||||
static readonly ScalarValuedFunction: SqlThemeIcon;
|
||||
static readonly TableValuedFunction: SqlThemeIcon;
|
||||
static readonly AggregateFunction: SqlThemeIcon;
|
||||
static readonly FileGroup: SqlThemeIcon;
|
||||
static readonly StoredProcedure: SqlThemeIcon;
|
||||
static readonly UserDefinedTableType: SqlThemeIcon;
|
||||
static readonly View: SqlThemeIcon;
|
||||
static readonly Table: SqlThemeIcon;
|
||||
static readonly HistoryTable: SqlThemeIcon;
|
||||
static readonly ServerLevelLinkedServerLogin: SqlThemeIcon;
|
||||
static readonly ServerLevelServerAudit: SqlThemeIcon;
|
||||
static readonly ServerLevelCryptographicProvider: SqlThemeIcon;
|
||||
static readonly ServerLevelCredential: SqlThemeIcon;
|
||||
static readonly ServerLevelServerRole: SqlThemeIcon;
|
||||
static readonly ServerLevelLogin: SqlThemeIcon;
|
||||
static readonly ServerLevelServerAuditSpecification: SqlThemeIcon;
|
||||
static readonly ServerLevelServerTrigger: SqlThemeIcon;
|
||||
static readonly ServerLevelLinkedServer: SqlThemeIcon;
|
||||
static readonly ServerLevelEndpoint: SqlThemeIcon;
|
||||
static readonly Synonym: SqlThemeIcon;
|
||||
static readonly DatabaseTrigger: SqlThemeIcon;
|
||||
static readonly Assembly: SqlThemeIcon;
|
||||
static readonly MessageType: SqlThemeIcon;
|
||||
static readonly Contract: SqlThemeIcon;
|
||||
static readonly Queue: SqlThemeIcon;
|
||||
static readonly Service: SqlThemeIcon;
|
||||
static readonly Route: SqlThemeIcon;
|
||||
static readonly DatabaseAndQueueEventNotification: SqlThemeIcon;
|
||||
static readonly RemoteServiceBinding: SqlThemeIcon;
|
||||
static readonly BrokerPriority: SqlThemeIcon;
|
||||
static readonly FullTextCatalog: SqlThemeIcon;
|
||||
static readonly FullTextStopList: SqlThemeIcon;
|
||||
static readonly SqlLogFile: SqlThemeIcon;
|
||||
static readonly PartitionFunction: SqlThemeIcon;
|
||||
static readonly PartitionScheme: SqlThemeIcon;
|
||||
static readonly SearchPropertyList: SqlThemeIcon;
|
||||
static readonly User: SqlThemeIcon;
|
||||
static readonly Schema: SqlThemeIcon;
|
||||
static readonly AsymmetricKey: SqlThemeIcon;
|
||||
static readonly Certificate: SqlThemeIcon;
|
||||
static readonly SymmetricKey: SqlThemeIcon;
|
||||
static readonly DatabaseEncryptionKey: SqlThemeIcon;
|
||||
static readonly MasterKey: SqlThemeIcon;
|
||||
static readonly DatabaseAuditSpecification: SqlThemeIcon;
|
||||
static readonly Column: SqlThemeIcon;
|
||||
static readonly Key: SqlThemeIcon;
|
||||
static readonly Constraint: SqlThemeIcon;
|
||||
static readonly Trigger: SqlThemeIcon;
|
||||
static readonly Index: SqlThemeIcon;
|
||||
static readonly Statistic: SqlThemeIcon;
|
||||
static readonly UserDefinedDataType: SqlThemeIcon;
|
||||
static readonly UserDefinedType: SqlThemeIcon;
|
||||
static readonly XmlSchemaCollection: SqlThemeIcon;
|
||||
static readonly SystemExactNumeric: SqlThemeIcon;
|
||||
static readonly SystemApproximateNumeric: SqlThemeIcon;
|
||||
static readonly SystemDateAndTime: SqlThemeIcon;
|
||||
static readonly SystemCharacterString: SqlThemeIcon;
|
||||
static readonly SystemUnicodeCharacterString: SqlThemeIcon;
|
||||
static readonly SystemBinaryString: SqlThemeIcon;
|
||||
static readonly SystemOtherDataType: SqlThemeIcon;
|
||||
static readonly SystemClrDataType: SqlThemeIcon;
|
||||
static readonly SystemSpatialDataType: SqlThemeIcon;
|
||||
static readonly UserDefinedTableTypeColumn: SqlThemeIcon;
|
||||
static readonly UserDefinedTableTypeKey: SqlThemeIcon;
|
||||
static readonly UserDefinedTableTypeConstraint: SqlThemeIcon;
|
||||
static readonly StoredProcedureParameter: SqlThemeIcon;
|
||||
static readonly TableValuedFunctionParameter: SqlThemeIcon;
|
||||
static readonly ScalarValuedFunctionParameter: SqlThemeIcon;
|
||||
static readonly AggregateFunctionParameter: SqlThemeIcon;
|
||||
static readonly DatabaseRole: SqlThemeIcon;
|
||||
static readonly ApplicationRole: SqlThemeIcon;
|
||||
static readonly FileGroupFile: SqlThemeIcon;
|
||||
static readonly SystemMessageType: SqlThemeIcon;
|
||||
static readonly SystemContract: SqlThemeIcon;
|
||||
static readonly SystemService: SqlThemeIcon;
|
||||
static readonly SystemQueue: SqlThemeIcon;
|
||||
static readonly Sequence: SqlThemeIcon;
|
||||
static readonly SecurityPolicy: SqlThemeIcon;
|
||||
static readonly DatabaseScopedCredential: SqlThemeIcon;
|
||||
static readonly ExternalResource: SqlThemeIcon;
|
||||
static readonly ExternalDataSource: SqlThemeIcon;
|
||||
static readonly ExternalFileFormat: SqlThemeIcon;
|
||||
static readonly ExternalTable: SqlThemeIcon;
|
||||
static readonly ColumnMasterKey: SqlThemeIcon;
|
||||
static readonly ColumnEncryptionKey: SqlThemeIcon;
|
||||
|
||||
private constructor(id: string);
|
||||
|
||||
/**
|
||||
* Gets the ID for the theme icon for help in cases where string comparison is needed
|
||||
*/
|
||||
public readonly id: string;
|
||||
}
|
||||
|
||||
// Object Explorer interfaces -----------------------------------------------------------------------
|
||||
@@ -1068,7 +1188,7 @@ declare module 'sqlops' {
|
||||
}
|
||||
|
||||
export enum FrequencyTypes {
|
||||
Unknown ,
|
||||
Unknown,
|
||||
OneTime = 1 << 1,
|
||||
Daily = 1 << 2,
|
||||
Weekly = 1 << 3,
|
||||
@@ -1276,15 +1396,14 @@ declare module 'sqlops' {
|
||||
job: AgentJobInfo;
|
||||
}
|
||||
|
||||
export interface AgentJobCategory
|
||||
{
|
||||
export interface AgentJobCategory {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface AgentJobDefaultsResult extends ResultStatus {
|
||||
owner: string;
|
||||
categories: AgentJobCategory[];
|
||||
categories: AgentJobCategory[];
|
||||
}
|
||||
|
||||
export interface CreateAgentJobStepResult extends ResultStatus {
|
||||
@@ -1384,6 +1503,9 @@ declare module 'sqlops' {
|
||||
updateProxy(ownerUri: string, originalProxyName: string, proxyInfo: AgentProxyInfo): Thenable<UpdateAgentOperatorResult>;
|
||||
deleteProxy(ownerUri: string, proxyInfo: AgentProxyInfo): Thenable<ResultStatus>;
|
||||
|
||||
// Credential method
|
||||
getCredentials(ownerUri: string): Thenable<GetCredentialsResult>;
|
||||
|
||||
// Job Schedule management methods
|
||||
getJobSchedules(ownerUri: string): Thenable<AgentJobSchedulesResult>;
|
||||
createJobSchedule(ownerUri: string, scheduleInfo: AgentJobScheduleInfo): Thenable<CreateAgentJobScheduleResult>;
|
||||
@@ -1393,6 +1515,20 @@ declare module 'sqlops' {
|
||||
registerOnUpdated(handler: () => any): void;
|
||||
}
|
||||
|
||||
// Security service interfaces ------------------------------------------------------------------------
|
||||
export interface CredentialInfo {
|
||||
id: number;
|
||||
identity: string;
|
||||
name: string;
|
||||
dateLastModified: string;
|
||||
createDate: string;
|
||||
providerName: string;
|
||||
}
|
||||
|
||||
export interface GetCredentialsResult extends ResultStatus {
|
||||
credentials: CredentialInfo[];
|
||||
}
|
||||
|
||||
// Task service interfaces ----------------------------------------------------------------------------
|
||||
export enum TaskStatus {
|
||||
notStarted = 0,
|
||||
|
||||
27
src/sql/sqlops.proposed.d.ts
vendored
27
src/sql/sqlops.proposed.d.ts
vendored
@@ -973,4 +973,31 @@ declare module 'sqlops' {
|
||||
*/
|
||||
export function getProvidersByType<T extends DataProvider>(providerType: DataProviderType): T[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Context object passed as an argument to command callbacks.
|
||||
* Defines the key properties required to identify a node in the object
|
||||
* explorer tree and take action against it.
|
||||
*/
|
||||
export interface ObjectExplorerContext {
|
||||
|
||||
/**
|
||||
* The connection information for the selected object.
|
||||
* Note that the connection is not guaranteed to be in a connected
|
||||
* state on click.
|
||||
*/
|
||||
connectionProfile: IConnectionProfile;
|
||||
/**
|
||||
* Defines whether this is a Connection-level object.
|
||||
* If not, the object is expected to be a child object underneath
|
||||
* one of the connections.
|
||||
*/
|
||||
isConnectionNode: boolean;
|
||||
/**
|
||||
* Node info for objects below a specific connection. This
|
||||
* may be null for a Connection-level object
|
||||
*/
|
||||
nodeInfo: NodeInfo;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -277,4 +277,102 @@ export enum DeclarativeDataType {
|
||||
export enum CardType {
|
||||
VerticalButton = 'VerticalButton',
|
||||
Details = 'Details'
|
||||
}
|
||||
}
|
||||
export class SqlThemeIcon {
|
||||
|
||||
static readonly Folder = new SqlThemeIcon('Folder');
|
||||
static readonly Root = new SqlThemeIcon('root');
|
||||
static readonly Database = new SqlThemeIcon('Database');
|
||||
static readonly Server = new SqlThemeIcon('Server');
|
||||
static readonly ScalarValuedFunction = new SqlThemeIcon('ScalarValuedFunction');
|
||||
static readonly TableValuedFunction = new SqlThemeIcon('TableValuedFunction');
|
||||
static readonly AggregateFunction = new SqlThemeIcon('AggregateFunction');
|
||||
static readonly FileGroup = new SqlThemeIcon('FileGroup');
|
||||
static readonly StoredProcedure = new SqlThemeIcon('StoredProcedure');
|
||||
static readonly UserDefinedTableType = new SqlThemeIcon('UserDefinedTableType');
|
||||
static readonly View = new SqlThemeIcon('View');
|
||||
static readonly Table = new SqlThemeIcon('Table');
|
||||
static readonly HistoryTable = new SqlThemeIcon('HistoryTable');
|
||||
static readonly ServerLevelLinkedServerLogin = new SqlThemeIcon('ServerLevelLinkedServerLogin');
|
||||
static readonly ServerLevelServerAudit = new SqlThemeIcon('ServerLevelServerAudit');
|
||||
static readonly ServerLevelCryptographicProvider = new SqlThemeIcon('ServerLevelCryptographicProvider');
|
||||
static readonly ServerLevelCredential = new SqlThemeIcon('ServerLevelCredential');
|
||||
static readonly ServerLevelServerRole = new SqlThemeIcon('ServerLevelServerRole');
|
||||
static readonly ServerLevelLogin = new SqlThemeIcon('ServerLevelLogin');
|
||||
static readonly ServerLevelServerAuditSpecification = new SqlThemeIcon('ServerLevelServerAuditSpecification');
|
||||
static readonly ServerLevelServerTrigger = new SqlThemeIcon('ServerLevelServerTrigger');
|
||||
static readonly ServerLevelLinkedServer = new SqlThemeIcon('ServerLevelLinkedServer');
|
||||
static readonly ServerLevelEndpoint = new SqlThemeIcon('ServerLevelEndpoint');
|
||||
static readonly Synonym = new SqlThemeIcon('Synonym');
|
||||
static readonly DatabaseTrigger = new SqlThemeIcon('DatabaseTrigger');
|
||||
static readonly Assembly = new SqlThemeIcon('Assembly');
|
||||
static readonly MessageType = new SqlThemeIcon('MessageType');
|
||||
static readonly Contract = new SqlThemeIcon('Contract');
|
||||
static readonly Queue = new SqlThemeIcon('Queue');
|
||||
static readonly Service = new SqlThemeIcon('Service');
|
||||
static readonly Route = new SqlThemeIcon('Route');
|
||||
static readonly DatabaseAndQueueEventNotification = new SqlThemeIcon('DatabaseAndQueueEventNotification');
|
||||
static readonly RemoteServiceBinding = new SqlThemeIcon('RemoteServiceBinding');
|
||||
static readonly BrokerPriority = new SqlThemeIcon('BrokerPriority');
|
||||
static readonly FullTextCatalog = new SqlThemeIcon('FullTextCatalog');
|
||||
static readonly FullTextStopList = new SqlThemeIcon('FullTextStopList');
|
||||
static readonly SqlLogFile = new SqlThemeIcon('SqlLogFile');
|
||||
static readonly PartitionFunction = new SqlThemeIcon('PartitionFunction');
|
||||
static readonly PartitionScheme = new SqlThemeIcon('PartitionScheme');
|
||||
static readonly SearchPropertyList = new SqlThemeIcon('SearchPropertyList');
|
||||
static readonly User = new SqlThemeIcon('User');
|
||||
static readonly Schema = new SqlThemeIcon('Schema');
|
||||
static readonly AsymmetricKey = new SqlThemeIcon('AsymmetricKey');
|
||||
static readonly Certificate = new SqlThemeIcon('Certificate');
|
||||
static readonly SymmetricKey = new SqlThemeIcon('SymmetricKey');
|
||||
static readonly DatabaseEncryptionKey = new SqlThemeIcon('DatabaseEncryptionKey');
|
||||
static readonly MasterKey = new SqlThemeIcon('MasterKey');
|
||||
static readonly DatabaseAuditSpecification = new SqlThemeIcon('DatabaseAuditSpecification');
|
||||
static readonly Column = new SqlThemeIcon('Column');
|
||||
static readonly Key = new SqlThemeIcon('Key');
|
||||
static readonly Constraint = new SqlThemeIcon('Constraint');
|
||||
static readonly Trigger = new SqlThemeIcon('Trigger');
|
||||
static readonly Index = new SqlThemeIcon('Index');
|
||||
static readonly Statistic = new SqlThemeIcon('Statistic');
|
||||
static readonly UserDefinedDataType = new SqlThemeIcon('UserDefinedDataType');
|
||||
static readonly UserDefinedType = new SqlThemeIcon('UserDefinedType');
|
||||
static readonly XmlSchemaCollection = new SqlThemeIcon('XmlSchemaCollection');
|
||||
static readonly SystemExactNumeric = new SqlThemeIcon('SystemExactNumeric');
|
||||
static readonly SystemApproximateNumeric = new SqlThemeIcon('SystemApproximateNumeric');
|
||||
static readonly SystemDateAndTime = new SqlThemeIcon('SystemDateAndTime');
|
||||
static readonly SystemCharacterString = new SqlThemeIcon('SystemCharacterString');
|
||||
static readonly SystemUnicodeCharacterString = new SqlThemeIcon('SystemUnicodeCharacterString');
|
||||
static readonly SystemBinaryString = new SqlThemeIcon('SystemBinaryString');
|
||||
static readonly SystemOtherDataType = new SqlThemeIcon('SystemOtherDataType');
|
||||
static readonly SystemClrDataType = new SqlThemeIcon('SystemClrDataType');
|
||||
static readonly SystemSpatialDataType = new SqlThemeIcon('SystemSpatialDataType');
|
||||
static readonly UserDefinedTableTypeColumn = new SqlThemeIcon('UserDefinedTableTypeColumn');
|
||||
static readonly UserDefinedTableTypeKey = new SqlThemeIcon('UserDefinedTableTypeKey');
|
||||
static readonly UserDefinedTableTypeConstraint = new SqlThemeIcon('UserDefinedTableTypeConstraint');
|
||||
static readonly StoredProcedureParameter = new SqlThemeIcon('StoredProcedureParameter');
|
||||
static readonly TableValuedFunctionParameter = new SqlThemeIcon('TableValuedFunctionParameter');
|
||||
static readonly ScalarValuedFunctionParameter = new SqlThemeIcon('ScalarValuedFunctionParameter');
|
||||
static readonly AggregateFunctionParameter = new SqlThemeIcon('AggregateFunctionParameter');
|
||||
static readonly DatabaseRole = new SqlThemeIcon('DatabaseRole');
|
||||
static readonly ApplicationRole = new SqlThemeIcon('ApplicationRole');
|
||||
static readonly FileGroupFile = new SqlThemeIcon('FileGroupFile');
|
||||
static readonly SystemMessageType = new SqlThemeIcon('SystemMessageType');
|
||||
static readonly SystemContract = new SqlThemeIcon('SystemContract');
|
||||
static readonly SystemService = new SqlThemeIcon('SystemService');
|
||||
static readonly SystemQueue = new SqlThemeIcon('SystemQueue');
|
||||
static readonly Sequence = new SqlThemeIcon('Sequence');
|
||||
static readonly SecurityPolicy = new SqlThemeIcon('SecurityPolicy');
|
||||
static readonly DatabaseScopedCredential = new SqlThemeIcon('DatabaseScopedCredential');
|
||||
static readonly ExternalResource = new SqlThemeIcon('ExternalResource');
|
||||
static readonly ExternalDataSource = new SqlThemeIcon('ExternalDataSource');
|
||||
static readonly ExternalFileFormat = new SqlThemeIcon('ExternalFileFormat');
|
||||
static readonly ExternalTable = new SqlThemeIcon('ExternalTable');
|
||||
static readonly ColumnMasterKey = new SqlThemeIcon('ColumnMasterKey');
|
||||
static readonly ColumnEncryptionKey = new SqlThemeIcon('ColumnEncryptionKey');
|
||||
|
||||
public readonly id: string;
|
||||
|
||||
private constructor(id: string) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,6 +604,13 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
||||
return this._resolveProvider<sqlops.AgentServicesProvider>(handle).deleteProxy(ownerUri, proxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Agent Credentials from server
|
||||
*/
|
||||
$getCredentials(handle: number, ownerUri: string): Thenable<sqlops.GetCredentialsResult> {
|
||||
return this._resolveProvider<sqlops.AgentServicesProvider>(handle).getCredentials(ownerUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL Agent job data update notification
|
||||
*/
|
||||
|
||||
@@ -366,6 +366,9 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
|
||||
deleteProxy(connectionUri: string, proxyInfo: sqlops.AgentProxyInfo): Thenable<sqlops.ResultStatus> {
|
||||
return self._proxy.$deleteProxy(handle, connectionUri, proxyInfo);
|
||||
},
|
||||
getCredentials(connectionUri: string): Thenable<sqlops.GetCredentialsResult> {
|
||||
return self._proxy.$getCredentials(handle, connectionUri);
|
||||
}
|
||||
});
|
||||
|
||||
return undefined;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user