mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-10 10:12:34 -05:00
Agent - bug fixes and mini features (#3637)
* fixed scrollbar in jobs * show steps tree when job history is opened * cleaned and added edit job to job history * scrollbars on step details * steps scrolling done * fixed styling * fixed keyboard selection, navigation and UI * fixed tabbing accessibility * added refresh action to job history * fixed focus on move step * added remove schedule button * fixed various bugs * added errors for all actions * review comments
This commit is contained in:
@@ -94,6 +94,9 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
private editStepButton: sqlops.ButtonComponent;
|
||||
private deleteStepButton: sqlops.ButtonComponent;
|
||||
|
||||
// Schedule tab controls
|
||||
private removeScheduleButton: sqlops.ButtonComponent;
|
||||
|
||||
// Notifications tab controls
|
||||
private notificationsTabTopLabel: sqlops.TextComponent;
|
||||
private emailCheckBox: sqlops.CheckBoxComponent;
|
||||
@@ -302,6 +305,7 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
this.stepsTable.data = this.convertStepsToData(this.steps);
|
||||
this.steps[previousRow].id = previousStepId;
|
||||
this.steps[rowNumber].id = currentStepId;
|
||||
this.stepsTable.selectedRows = [previousRow];
|
||||
});
|
||||
|
||||
this.moveStepDownButton.onDidClick(() => {
|
||||
@@ -316,6 +320,7 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
this.stepsTable.data = this.convertStepsToData(this.steps);
|
||||
this.steps[nextRow].id = nextStepId;
|
||||
this.steps[rowNumber].id = currentStepId;
|
||||
this.stepsTable.selectedRows = [nextRow];
|
||||
});
|
||||
|
||||
this.editStepButton.onDidClick(() => {
|
||||
@@ -346,20 +351,30 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
if (this.stepsTable.selectedRows.length === 1) {
|
||||
let rowNumber = this.stepsTable.selectedRows[0];
|
||||
AgentUtils.getAgentService().then((agentService) => {
|
||||
let steps = this.model.jobSteps ? this.model.jobSteps : [];
|
||||
let stepData = this.model.jobSteps[rowNumber];
|
||||
agentService.deleteJobStep(this.ownerUri, stepData).then((result) => {
|
||||
if (result && result.success) {
|
||||
delete steps[rowNumber];
|
||||
let data = this.convertStepsToData(steps);
|
||||
this.stepsTable.data = data;
|
||||
this.startStepDropdownValues = [];
|
||||
this.steps.forEach((step) => {
|
||||
this.startStepDropdownValues.push({ displayName: step.id + ': ' + step.stepName, name: step.id.toString() });
|
||||
});
|
||||
this.startStepDropdown.values = this.startStepDropdownValues;
|
||||
}
|
||||
});
|
||||
let stepData = this.steps[rowNumber];
|
||||
if (stepData.jobId) {
|
||||
agentService.deleteJobStep(this.ownerUri, stepData).then((result) => {
|
||||
if (result && result.success) {
|
||||
this.steps.splice(rowNumber, 1);
|
||||
let data = this.convertStepsToData(this.steps);
|
||||
this.stepsTable.data = data;
|
||||
this.startStepDropdownValues = [];
|
||||
this.steps.forEach((step) => {
|
||||
this.startStepDropdownValues.push({ displayName: step.id + ': ' + step.stepName, name: step.id.toString() });
|
||||
});
|
||||
this.startStepDropdown.values = this.startStepDropdownValues;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.steps.splice(rowNumber, 1);
|
||||
let data = this.convertStepsToData(this.steps);
|
||||
this.stepsTable.data = data;
|
||||
this.startStepDropdownValues = [];
|
||||
this.steps.forEach((step) => {
|
||||
this.startStepDropdownValues.push({ displayName: step.id + ': ' + step.stepName, name: step.id.toString() });
|
||||
});
|
||||
this.startStepDropdown.values = this.startStepDropdownValues;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -468,7 +483,11 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
label: this.PickScheduleButtonString,
|
||||
width: 80
|
||||
}).component();
|
||||
this.pickScheduleButton.onDidClick((e)=>{
|
||||
this.removeScheduleButton = view.modelBuilder.button().withProperties({
|
||||
label: 'Remove schedule',
|
||||
width: 100
|
||||
}).component();
|
||||
this.pickScheduleButton.onDidClick(()=>{
|
||||
let pickScheduleDialog = new PickScheduleDialog(this.model.ownerUri, this.model.name);
|
||||
pickScheduleDialog.onSuccess((dialogModel) => {
|
||||
let selectedSchedule = dialogModel.selectedSchedule;
|
||||
@@ -483,12 +502,23 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
});
|
||||
pickScheduleDialog.showDialog();
|
||||
});
|
||||
|
||||
this.removeScheduleButton.onDidClick(() => {
|
||||
if (this.schedulesTable.selectedRows.length === 1) {
|
||||
let selectedRow = this.schedulesTable.selectedRows[0];
|
||||
let selectedScheduleName = this.schedulesTable.data[selectedRow][1];
|
||||
for (let i = 0; i < this.schedules.length; i++) {
|
||||
if (this.schedules[i].name === selectedScheduleName) {
|
||||
this.schedules.splice(i, 1);
|
||||
}
|
||||
}
|
||||
this.populateScheduleTable();
|
||||
}
|
||||
});
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.schedulesTable,
|
||||
title: this.SchedulesTopLabelString,
|
||||
actions: [this.pickScheduleButton]
|
||||
actions: [this.pickScheduleButton, this.removeScheduleButton]
|
||||
}]).withLayout({ width: '100%' }).component();
|
||||
|
||||
await view.initializeModel(formModel);
|
||||
@@ -499,10 +529,9 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
|
||||
private populateScheduleTable() {
|
||||
let data = this.convertSchedulesToData(this.schedules);
|
||||
if (data.length > 0) {
|
||||
this.schedulesTable.data = data;
|
||||
this.schedulesTable.height = 750;
|
||||
}
|
||||
this.schedulesTable.data = data;
|
||||
this.schedulesTable.height = 750;
|
||||
|
||||
}
|
||||
|
||||
private initializeNotificationsTab() {
|
||||
@@ -674,5 +703,6 @@ export class JobDialog extends AgentDialog<JobData> {
|
||||
this.model.alerts = [];
|
||||
}
|
||||
this.model.alerts = this.alerts;
|
||||
this.model.categoryId = +this.model.jobCategoryIdsMap.find(cat => cat.name === this.model.category).id;
|
||||
}
|
||||
}
|
||||
@@ -29,11 +29,10 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
||||
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.');
|
||||
private readonly BlankStepNameErrorText: string = localize('jobStepDialog.blankStepName', 'The step name cannot be left blank');
|
||||
private readonly ProcessExitCodeText: string = localize('jobStepDialog.processExitCode', 'Process exit code of a successful command:');
|
||||
|
||||
// General Control Titles
|
||||
private readonly StepNameLabelString: string = localize('jobStepDialog.stepNameLabel', 'Step Name');
|
||||
@@ -62,6 +61,8 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
||||
|
||||
// Dropdown options
|
||||
private readonly TSQLScript: string = localize('jobStepDialog.TSQL', 'Transact-SQL script (T-SQL)');
|
||||
private readonly Powershell: string = localize('jobStepDialog.powershell', 'PowerShell');
|
||||
private readonly CmdExec: string = localize('jobStepDialog.CmdExec', 'Operating system (CmdExec)');
|
||||
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');
|
||||
@@ -88,6 +89,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
||||
private outputFileNameBox: sqlops.InputBoxComponent;
|
||||
private fileBrowserNameBox: sqlops.InputBoxComponent;
|
||||
private userInputBox: sqlops.InputBoxComponent;
|
||||
private processExitCodeBox: sqlops.InputBoxComponent;
|
||||
|
||||
// Dropdowns
|
||||
private typeDropdown: sqlops.DropDownComponent;
|
||||
@@ -100,8 +102,6 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
||||
// Buttons
|
||||
private openButton: sqlops.ButtonComponent;
|
||||
private parseButton: sqlops.ButtonComponent;
|
||||
private nextButton: sqlops.ButtonComponent;
|
||||
private previousButton: sqlops.ButtonComponent;
|
||||
private outputFileBrowserButton: sqlops.ButtonComponent;
|
||||
|
||||
// Checkbox
|
||||
@@ -179,18 +179,6 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
||||
inputType: 'text'
|
||||
})
|
||||
.component();
|
||||
this.nextButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: this.NextButtonText,
|
||||
enabled: false,
|
||||
width: '80px'
|
||||
}).component();
|
||||
this.previousButton = view.modelBuilder.button()
|
||||
.withProperties({
|
||||
label: this.PreviousButtonText,
|
||||
enabled: false,
|
||||
width: '80px'
|
||||
}).component();
|
||||
}
|
||||
|
||||
private createGeneralTab(databases: string[], queryProvider: sqlops.QueryProvider) {
|
||||
@@ -208,7 +196,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
||||
this.typeDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: this.TSQLScript,
|
||||
values: [this.TSQLScript]
|
||||
values: [this.TSQLScript, this.CmdExec, this.Powershell]
|
||||
})
|
||||
.component();
|
||||
this.runAsDropdown = view.modelBuilder.dropDown()
|
||||
@@ -218,33 +206,20 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
||||
})
|
||||
.component();
|
||||
this.runAsDropdown.enabled = false;
|
||||
this.typeDropdown.onValueChanged((type) => {
|
||||
if (type.selected !== this.TSQLScript) {
|
||||
this.runAsDropdown.value = this.AgentServiceAccount;
|
||||
this.runAsDropdown.values = [this.runAsDropdown.value];
|
||||
} else {
|
||||
this.runAsDropdown.value = '';
|
||||
this.runAsDropdown.values = [''];
|
||||
}
|
||||
});
|
||||
this.databaseDropdown = view.modelBuilder.dropDown()
|
||||
.withProperties({
|
||||
value: databases[0],
|
||||
values: databases
|
||||
}).component();
|
||||
|
||||
this.processExitCodeBox = view.modelBuilder.inputBox()
|
||||
.withProperties({
|
||||
}).component();
|
||||
this.processExitCodeBox.enabled = false;
|
||||
|
||||
// create the commands section
|
||||
this.createCommands(view, queryProvider);
|
||||
|
||||
let buttonContainer = view.modelBuilder.flexContainer()
|
||||
.withLayout({
|
||||
flexFlow: 'row',
|
||||
justifyContent: 'space-between',
|
||||
width: 420
|
||||
}).withItems([this.openButton, this.parseButton, this.previousButton, this.nextButton], {
|
||||
flex: '1 1 50%'
|
||||
}).component();
|
||||
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: this.nameTextBox,
|
||||
@@ -258,14 +233,52 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
||||
}, {
|
||||
component: this.databaseDropdown,
|
||||
title: this.DatabaseLabelString
|
||||
}, {
|
||||
component: this.processExitCodeBox,
|
||||
title: this.ProcessExitCodeText
|
||||
}, {
|
||||
component: this.commandTextBox,
|
||||
title: this.CommandLabelString,
|
||||
actions: [buttonContainer]
|
||||
actions: [this.openButton, this.parseButton]
|
||||
}], {
|
||||
horizontal: false,
|
||||
componentWidth: 420
|
||||
}).component();
|
||||
this.typeDropdown.onValueChanged((type) => {
|
||||
switch (type.selected) {
|
||||
case(this.TSQLScript):
|
||||
this.runAsDropdown.value = '';
|
||||
this.runAsDropdown.values = [''];
|
||||
this.runAsDropdown.enabled = false;
|
||||
this.databaseDropdown.enabled = true;
|
||||
this.databaseDropdown.values = databases;
|
||||
this.databaseDropdown.value = databases[0];
|
||||
this.processExitCodeBox.value = '';
|
||||
this.processExitCodeBox.enabled = false;
|
||||
break;
|
||||
case(this.Powershell):
|
||||
this.runAsDropdown.value = this.AgentServiceAccount;
|
||||
this.runAsDropdown.values = [this.runAsDropdown.value];
|
||||
this.runAsDropdown.enabled = true;
|
||||
this.databaseDropdown.enabled = false;
|
||||
this.databaseDropdown.values = [''];
|
||||
this.databaseDropdown.value = '';
|
||||
this.processExitCodeBox.value = '';
|
||||
this.processExitCodeBox.enabled = false;
|
||||
break;
|
||||
case(this.CmdExec):
|
||||
this.databaseDropdown.enabled = false;
|
||||
this.databaseDropdown.values = [''];
|
||||
this.databaseDropdown.value = '';
|
||||
this.runAsDropdown.value = this.AgentServiceAccount;
|
||||
this.runAsDropdown.values = [this.runAsDropdown.value];
|
||||
this.runAsDropdown.enabled = true;
|
||||
this.processExitCodeBox.enabled = true;
|
||||
this.processExitCodeBox.value = '0';
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
let formWrapper = view.modelBuilder.loadingComponent().withItem(formModel).component();
|
||||
formWrapper.loading = false;
|
||||
await view.initializeModel(formWrapper);
|
||||
@@ -524,6 +537,7 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
|
||||
this.model.outputFileName = this.outputFileNameBox.value;
|
||||
this.model.appendToLogFile = this.appendToExistingFileCheckbox.checked;
|
||||
this.model.command = this.commandTextBox.value ? this.commandTextBox.value : '';
|
||||
this.model.commandExecutionSuccessCode = this.processExitCodeBox.value ? +this.processExitCodeBox.value : 0;
|
||||
}
|
||||
|
||||
public async initializeDialog() {
|
||||
|
||||
Reference in New Issue
Block a user