diff --git a/extensions/agent/src/data/jobData.ts b/extensions/agent/src/data/jobData.ts index 1d512edd62..fc995fd59b 100644 --- a/extensions/agent/src/data/jobData.ts +++ b/extensions/agent/src/data/jobData.ts @@ -45,6 +45,7 @@ export class JobData implements IAgentDialogData { public jobSchedules: sqlops.AgentJobScheduleInfo[]; public alerts: sqlops.AgentAlertInfo[]; public jobId: string; + public startStepId: number; constructor( ownerUri: string, @@ -60,10 +61,11 @@ export class JobData implements IAgentDialogData { this.category = jobInfo.category; this.description = jobInfo.description; this.enabled = jobInfo.enabled; - this.jobSteps = jobInfo.JobSteps; - this.jobSchedules = jobInfo.JobSchedules; - this.alerts = jobInfo.Alerts; + this.jobSteps = jobInfo.jobSteps; + this.jobSchedules = jobInfo.jobSchedules; + this.alerts = jobInfo.alerts; this.jobId = jobInfo.jobId; + this.startStepId = jobInfo.startStepId; } } @@ -141,17 +143,17 @@ export class JobData implements IAgentDialogData { name: this.name, owner: this.owner, description: this.description, - EmailLevel: this.emailLevel, - PageLevel: this.pageLevel, - EventLogLevel: this.eventLogLevel, - DeleteLevel: this.deleteLevel, - OperatorToEmail: this.operatorToEmail, - OperatorToPage: this.operatorToPage, + emailLevel: this.emailLevel, + pageLevel: this.pageLevel, + eventLogLevel: this.eventLogLevel, + deleteLevel: this.deleteLevel, + operatorToEmail: this.operatorToEmail, + operatorToPage: this.operatorToPage, enabled: this.enabled, category: this.category, - Alerts: this.alerts, - JobSchedules: this.jobSchedules, - JobSteps: this.jobSteps, + alerts: this.alerts, + jobSchedules: this.jobSchedules, + jobSteps: this.jobSteps, // The properties below are not collected from UI // We could consider using a seperate class for create job request // @@ -166,7 +168,8 @@ export class JobData implements IAgentDialogData { categoryType: 1, // LocalJob, hard-coding the value, corresponds to the target tab in SSMS lastRun: '', nextRun: '', - jobId: this.jobId + jobId: this.jobId, + startStepId: this.startStepId }; } } \ No newline at end of file diff --git a/extensions/agent/src/dialogs/jobDialog.ts b/extensions/agent/src/dialogs/jobDialog.ts index 6111eacae4..8b438c5e80 100644 --- a/extensions/agent/src/dialogs/jobDialog.ts +++ b/extensions/agent/src/dialogs/jobDialog.ts @@ -42,11 +42,12 @@ export class JobDialog extends AgentDialog { 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 NewStepButtonString: string = localize('jobDialog.new', 'New Step'); + private readonly EditStepButtonString: string = localize('jobDialog.edit', 'Edit Step'); + private readonly DeleteStepButtonString: string = localize('jobDialog.delete', 'Delete Step'); private readonly MoveStepUpButtonString: string = localize('jobDialog.moveUp', 'Move Step Up'); private readonly MoveStepDownButtonString: string = localize('jobDialog.moveDown', 'Move Step Down'); + private readonly StartStepDropdownString: string = localize('jobDialog.startStepAt', 'Start step'); // Notifications tab strings private readonly NotificationsTabTopLabelString: string = localize('jobDialog.notificationsTabTop', 'Actions to perform when the job completes'); @@ -105,6 +106,7 @@ export class JobDialog extends AgentDialog { private eventLogConditionDropdown: sqlops.DropDownComponent; private deleteJobCheckBox: sqlops.CheckBoxComponent; private deleteJobConditionDropdown: sqlops.DropDownComponent; + private startStepDropdown: sqlops.DropDownComponent; // Schedule tab controls private schedulesTable: sqlops.TableComponent; @@ -119,6 +121,7 @@ export class JobDialog extends AgentDialog { private steps: sqlops.AgentJobStepInfo[]; private schedules: sqlops.AgentJobScheduleInfo[]; private alerts: sqlops.AgentAlertInfo[] = []; + private startStepDropdownValues: sqlops.CategoryValue[] = []; constructor(ownerUri: string, jobInfo: sqlops.AgentJobInfo = undefined) { super( @@ -223,13 +226,20 @@ export class JobDialog extends AgentDialog { this.StepsTable_FailureColumnString ], data: data, - height: 750 + height: 650 }).component(); + this.startStepDropdown = view.modelBuilder.dropDown().withProperties({ width: 180 }).component(); + this.startStepDropdown.enabled = this.steps.length > 1 ? true : false; + this.steps.forEach((step) => { + this.startStepDropdownValues.push({ displayName: step.id + ': ' + step.stepName, name: step.id.toString() }); + }); + this.startStepDropdown.values = this.startStepDropdownValues; + this.moveStepUpButton = view.modelBuilder.button() .withProperties({ label: this.MoveStepUpButtonString, - width: 80 + width: 120 }).component(); this.moveStepDownButton = view.modelBuilder.button() @@ -243,7 +253,7 @@ export class JobDialog extends AgentDialog { this.newStepButton = view.modelBuilder.button().withProperties({ label: this.NewStepButtonString, - width: 80 + width: 140 }).component(); let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, null, true); @@ -251,6 +261,11 @@ export class JobDialog extends AgentDialog { let stepInfo = JobStepData.convertToAgentJobStepInfo(step); this.steps.push(stepInfo); this.stepsTable.data = this.convertStepsToData(this.steps); + this.startStepDropdownValues = []; + this.steps.forEach((step) => { + this.startStepDropdownValues.push({ displayName: step.id + ': ' + step.stepName, name: step.id.toString() }); + }); + this.startStepDropdown.values = this.startStepDropdownValues; }); this.newStepButton.onDidClick((e)=>{ if (this.nameTextBox.value && this.nameTextBox.value.length > 0) { @@ -263,12 +278,12 @@ export class JobDialog extends AgentDialog { this.editStepButton = view.modelBuilder.button().withProperties({ label: this.EditStepButtonString, - width: 80 + width: 140 }).component(); this.deleteStepButton = view.modelBuilder.button().withProperties({ label: this.DeleteStepButtonString, - width: 80 + width: 140 }).component(); this.stepsTable.enabled = false; @@ -276,41 +291,31 @@ export class JobDialog extends AgentDialog { this.deleteStepButton.enabled = false; this.moveStepUpButton.onDidClick(() => { - if (this.stepsTable.selectedRows.length === 1) { - let rowNumber = this.stepsTable.selectedRows[0]; - // if it's not the first step - if (rowNumber !== 0) { - let previousRow = rowNumber - 1; - let previousStep = this.steps[previousRow]; - let previousStepId = this.steps[previousRow].id; - let currentStep = this.steps[rowNumber]; - let currentStepId = this.steps[rowNumber].id; - this.steps[previousRow] = currentStep; - this.steps[rowNumber] = previousStep; - this.stepsTable.data = this.convertStepsToData(this.steps); - this.steps[previousRow].id = previousStepId; - this.steps[rowNumber].id = currentStepId; - } - } + let rowNumber = this.stepsTable.selectedRows[0]; + let previousRow = rowNumber - 1; + let previousStep = this.steps[previousRow]; + let previousStepId = this.steps[previousRow].id; + let currentStep = this.steps[rowNumber]; + let currentStepId = this.steps[rowNumber].id; + this.steps[previousRow] = currentStep; + this.steps[rowNumber] = previousStep; + this.stepsTable.data = this.convertStepsToData(this.steps); + this.steps[previousRow].id = previousStepId; + this.steps[rowNumber].id = currentStepId; }); this.moveStepDownButton.onDidClick(() => { - if (this.stepsTable.selectedRows.length === 1) { - let rowNumber = this.stepsTable.selectedRows[0]; - // if it's not the last step - if (this.steps.length !== rowNumber + 1) { - let nextRow = rowNumber + 1; - let nextStep = this.steps[nextRow]; - let nextStepId = this.steps[nextRow].id; - let currentStep = this.steps[rowNumber]; - let currentStepId = this.steps[rowNumber].id; - this.steps[nextRow] = currentStep; - this.steps[rowNumber] = nextStep; - this.stepsTable.data = this.convertStepsToData(this.steps); - this.steps[nextRow].id = nextStepId; - this.steps[rowNumber].id = currentStepId; - } - } + let rowNumber = this.stepsTable.selectedRows[0]; + let nextRow = rowNumber + 1; + let nextStep = this.steps[nextRow]; + let nextStepId = this.steps[nextRow].id; + let currentStep = this.steps[rowNumber]; + let currentStepId = this.steps[rowNumber].id; + this.steps[nextRow] = currentStep; + this.steps[rowNumber] = nextStep; + this.stepsTable.data = this.convertStepsToData(this.steps); + this.steps[nextRow].id = nextStepId; + this.steps[rowNumber].id = currentStepId; }); this.editStepButton.onDidClick(() => { @@ -326,6 +331,12 @@ export class JobDialog extends AgentDialog { } } this.stepsTable.data = this.convertStepsToData(this.steps); + this.startStepDropdownValues = []; + this.steps.forEach((step) => { + this.startStepDropdownValues.push({ displayName: step.id + ': ' + step.stepName, name: step.id.toString() }); + }); + this.startStepDropdown.values = this.startStepDropdownValues; + }); editStepDialog.openDialog(); } @@ -342,30 +353,52 @@ export class JobDialog extends AgentDialog { 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; } }); }); } }); - this.stepsTable.onRowSelected(() => { + this.stepsTable.onRowSelected((row) => { // only let edit or delete steps if there's // one step selection if (this.stepsTable.selectedRows.length === 1) { - this.moveStepUpButton.enabled = true; - this.moveStepDownButton.enabled = true; + let rowNumber = this.stepsTable.selectedRows[0]; + // if it's not the last step + if (this.steps.length !== rowNumber + 1) { + this.moveStepDownButton.enabled = true; + } + // if it's not the first step + if (rowNumber !== 0) { + this.moveStepUpButton.enabled = true; + } this.deleteStepButton.enabled = true; this.editStepButton.enabled = true; } }); - - let formModel = view.modelBuilder.formContainer() - .withFormItems([{ + let stepMoveContainer = this.createRowContainer(view).withItems([this.startStepDropdown, this.moveStepUpButton, this.moveStepDownButton]).component(); + let stepsDialogContainer = this.createRowContainer(view).withItems([this.newStepButton, this.editStepButton, this.deleteStepButton]).component(); + let formModel = view.modelBuilder.formContainer().withFormItems([ + { component: this.stepsTable, - title: this.JobStepsTopLabelString, - actions: [this.moveStepUpButton, this.moveStepDownButton, this.newStepButton, this.editStepButton, this.deleteStepButton] - }]).withLayout({ width: '100%' }).component(); + title: this.JobStepsTopLabelString + }, + { + component: stepMoveContainer, + title: this.StartStepDropdownString + }, + { + component: stepsDialogContainer, + title: '' + } + ]).withLayout({ width: '100%' }).component(); await view.initializeModel(formModel); + this.setConditionDropdownSelectedValue(this.startStepDropdown, this.model.startStepId); }); } @@ -628,6 +661,7 @@ export class JobDialog extends AgentDialog { this.model.pageLevel = this.getActualConditionValue(this.pagerCheckBox, this.pagerConditionDropdown); this.model.eventLogLevel = this.getActualConditionValue(this.eventLogCheckBox, this.eventLogConditionDropdown); this.model.deleteLevel = this.getActualConditionValue(this.deleteJobCheckBox, this.deleteJobConditionDropdown); + this.model.startStepId = +this.getDropdownValue(this.startStepDropdown); if (!this.model.jobSteps) { this.model.jobSteps = []; } diff --git a/src/sql/parts/jobManagement/views/jobsView.component.ts b/src/sql/parts/jobManagement/views/jobsView.component.ts index 882cad38a8..7eae1f13ac 100644 --- a/src/sql/parts/jobManagement/views/jobsView.component.ts +++ b/src/sql/parts/jobManagement/views/jobsView.component.ts @@ -937,19 +937,19 @@ export class JobsViewComponent extends JobManagementView implements OnInit, OnDe // add steps if (this.jobSteps && this.jobSteps[jobId]) { let steps = this.jobSteps[jobId]; - job[0].JobSteps = steps; + job[0].jobSteps = steps; } // add schedules if (this.jobSchedules && this.jobSchedules[jobId]) { let schedules = this.jobSchedules[jobId]; - job[0].JobSchedules = schedules; + job[0].jobSchedules = schedules; } // add alerts if (this.jobAlerts && this.jobAlerts[jobId]) { let alerts = this.jobAlerts[jobId]; - job[0].Alerts = alerts; + job[0].alerts = alerts; } return job && job.length > 0 ? job[0] : undefined; } diff --git a/src/sql/sqlops.d.ts b/src/sql/sqlops.d.ts index 2450549a2a..cf40c14bd4 100644 --- a/src/sql/sqlops.d.ts +++ b/src/sql/sqlops.d.ts @@ -1300,15 +1300,16 @@ declare module 'sqlops' { lastRun: string; nextRun: string; jobId: string; - EmailLevel: JobCompletionActionCondition; - PageLevel: JobCompletionActionCondition; - EventLogLevel: JobCompletionActionCondition; - DeleteLevel: JobCompletionActionCondition; - OperatorToEmail: string; - OperatorToPage: string; - JobSteps: AgentJobStepInfo[]; - JobSchedules: AgentJobScheduleInfo[]; - Alerts: AgentAlertInfo[]; + startStepId: number; + emailLevel: JobCompletionActionCondition; + pageLevel: JobCompletionActionCondition; + eventLogLevel: JobCompletionActionCondition; + deleteLevel: JobCompletionActionCondition; + operatorToEmail: string; + operatorToPage: string; + jobSteps: AgentJobStepInfo[]; + jobSchedules: AgentJobScheduleInfo[]; + alerts: AgentAlertInfo[]; } export interface AgentJobScheduleInfo {