Agent/edit job logic (#3023)

* lumped stepdata with jobdata in job dialog

* fix bug with empty steps

* added clumped and update steps and schedules from job dialog

* edit data sends one call instead of multiple

* cleaned code
This commit is contained in:
Aditya Bist
2018-10-31 16:40:36 -07:00
committed by Karl Burtram
parent a06f80bdb1
commit db2d380b6c
10 changed files with 129 additions and 111 deletions

View File

@@ -9,6 +9,7 @@ import * as vscode from 'vscode';
import * as sqlops from 'sqlops';
import { AgentUtils } from '../agentUtils';
import { IAgentDialogData, AgentDialogMode } from '../interfaces';
import { JobData } from './jobData';
const localize = nls.loadMessageBundle();
@@ -45,8 +46,19 @@ export class AlertData implements IAgentDialogData {
wmiEventNamespace: string;
wmiEventQuery: string;
constructor(ownerUri:string, alertInfo: sqlops.AgentAlertInfo) {
private viaJobDialog: boolean;
private jobModel: JobData;
constructor(
ownerUri:string,
alertInfo: sqlops.AgentAlertInfo,
jobModel?: JobData,
viaJobDialog: boolean = false
) {
this.ownerUri = ownerUri;
this.viaJobDialog = viaJobDialog;
this.jobModel = jobModel;
this.jobName = this.jobName ? this.jobName : this.jobModel.name;
if (alertInfo) {
this.dialogMode = AgentDialogMode.EDIT;
@@ -60,7 +72,6 @@ export class AlertData implements IAgentDialogData {
this.includeEventDescription = alertInfo.includeEventDescription.toString();
this.isEnabled = alertInfo.isEnabled;
this.jobId = alertInfo.jobId;
this.jobName = alertInfo.jobName;
this.lastOccurrenceDate = alertInfo.lastOccurrenceDate;
this.lastResponseDate = alertInfo.lastResponseDate;
this.messageId = alertInfo.messageId;
@@ -82,10 +93,18 @@ export class AlertData implements IAgentDialogData {
public async save() {
let agentService = await AgentUtils.getAgentService();
let result = this.dialogMode === AgentDialogMode.CREATE
? await agentService.createAlert(this.ownerUri, this.toAgentAlertInfo())
: await agentService.updateAlert(this.ownerUri, this.originalName, this.toAgentAlertInfo());
let result: any;
// if it's called via the job dialog, add it to the
// job model
if (this.viaJobDialog) {
if (this.jobModel) {
Promise.resolve(this);
return;
}
} else {
// has to be a create alert
result = await agentService.createAlert(this.ownerUri, this.toAgentAlertInfo());
}
if (!result || !result.success) {
vscode.window.showErrorMessage(
localize('alertData.saveErrorMessage', "Alert update failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown'));

View File

@@ -44,6 +44,7 @@ export class JobData implements IAgentDialogData {
public jobSteps: sqlops.AgentJobStepInfo[];
public jobSchedules: sqlops.AgentJobScheduleInfo[];
public alerts: sqlops.AgentAlertInfo[];
public jobId: string;
constructor(
ownerUri: string,
@@ -62,6 +63,7 @@ export class JobData implements IAgentDialogData {
this.jobSteps = jobInfo.JobSteps;
this.jobSchedules = jobInfo.JobSchedules;
this.alerts = jobInfo.Alerts;
this.jobId = jobInfo.jobId;
}
}
@@ -115,7 +117,6 @@ export class JobData implements IAgentDialogData {
let result = this.dialogMode === AgentDialogMode.CREATE
? await this._agentService.createJob(this.ownerUri, jobInfo)
: await this._agentService.updateJob(this.ownerUri, this.originalName, jobInfo);
if (!result || !result.success) {
vscode.window.showErrorMessage(
localize('jobData.saveErrorMessage', "Job update failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown'));
@@ -135,18 +136,6 @@ export class JobData implements IAgentDialogData {
};
}
public addJobSchedule(schedule: sqlops.AgentJobScheduleInfo) {
if (this.jobSchedules) {
let existingSchedule = this.jobSchedules.find(item => item.name === schedule.name);
if (!existingSchedule) {
this.jobSchedules.push(schedule);
}
} else {
this.jobSchedules = [];
this.jobSchedules.push(schedule);
}
}
public toAgentJobInfo(): sqlops.AgentJobInfo {
return {
name: this.name,
@@ -177,7 +166,7 @@ export class JobData implements IAgentDialogData {
categoryType: 1, // LocalJob, hard-coding the value, corresponds to the target tab in SSMS
lastRun: '',
nextRun: '',
jobId: ''
jobId: this.jobId
};
}
}

View File

@@ -46,11 +46,13 @@ export class JobStepData implements IAgentDialogData {
public retryInterval: number;
public proxyName: string;
private jobModel: JobData;
private viaJobDialog: boolean;
constructor(ownerUri:string, jobModel?: JobData) {
constructor(ownerUri:string, jobModel?: JobData, viaJobDialog: boolean = false) {
this.ownerUri = ownerUri;
this.jobName = jobModel.name;
this.jobModel = jobModel;
this.viaJobDialog = viaJobDialog;
}
public async initialize() {
@@ -59,18 +61,16 @@ export class JobStepData implements IAgentDialogData {
public async save() {
let agentService = await AgentUtils.getAgentService();
let result: any;
if (this.dialogMode === AgentDialogMode.CREATE) {
if (this.jobModel && this.jobModel.dialogMode === AgentDialogMode.CREATE) {
// create job -> create step
// if it's called via the job dialog, add it to the
// job model
if (this.viaJobDialog) {
if (this.jobModel) {
Promise.resolve(this);
return;
} else {
// edit job -> create step
result = await agentService.createJobStep(this.ownerUri, JobStepData.convertToAgentJobStepInfo(this));
}
} else if (this.jobModel && this.jobModel.dialogMode === AgentDialogMode.EDIT) {
// edit job -> edit step
result = await agentService.updateJobStep(this.ownerUri, this.stepName, JobStepData.convertToAgentJobStepInfo(this));
} else {
// has to be a create step
result = await agentService.createJobStep(this.ownerUri, JobStepData.convertToAgentJobStepInfo(this));
}
if (!result || !result.success) {
vscode.window.showErrorMessage(

View File

@@ -29,8 +29,6 @@ export class PickScheduleData implements IAgentDialogData {
}
public async save() {
let agentService = await AgentUtils.getAgentService();
this.selectedSchedule.jobName = this.jobName;
let result = await agentService.createJobSchedule(this.ownerUri, this.selectedSchedule);
}
}

View File

@@ -12,6 +12,7 @@ import { AgentUtils } from '../agentUtils';
import { AlertData } from '../data/alertData';
import { OperatorDialog } from './operatorDialog';
import { JobDialog } from './jobDialog';
import { JobData } from '../data/jobData';
const localize = nls.loadMessageBundle();
@@ -148,14 +149,23 @@ export class AlertDialog extends AgentDialog<AlertData> {
private delayMinutesTextBox: sqlops.InputBoxComponent;
private delaySecondsTextBox: sqlops.InputBoxComponent;
private jobs: string[];
private databases: string[];
private jobModel: JobData;
public jobId: string;
public jobName: string;
constructor(ownerUri: string, alertInfo: sqlops.AgentAlertInfo = undefined, jobs: string[]) {
constructor(
ownerUri: string,
jobModel: JobData,
alertInfo: sqlops.AgentAlertInfo = undefined,
viaJobDialog: boolean = false
) {
super(ownerUri,
new AlertData(ownerUri, alertInfo),
new AlertData(ownerUri, alertInfo, jobModel, viaJobDialog),
alertInfo ? AlertDialog.EditDialogTitle : AlertDialog.CreateDialogTitle);
this.jobs = jobs;
this.jobModel = jobModel;
this.jobId = this.jobId ? this.jobId : this.jobModel.jobId;
this.jobName = this.jobName ? this.jobName : this.jobModel.name;
}
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
@@ -512,7 +522,8 @@ export class AlertDialog extends AgentDialog<AlertData> {
protected updateModel() {
this.model.name = this.nameTextBox.value;
this.model.isEnabled = this.enabledCheckBox.checked;
this.model.jobId = this.jobId;
this.model.jobName = this.jobName;
this.model.alertType = this.getDropdownValue(this.typeDropDown);
let databaseName = this.getDropdownValue(this.databaseDropDown);
this.model.databaseName = (databaseName !== AlertDialog.AllDatabases) ? databaseName : undefined;

View File

@@ -11,6 +11,7 @@ import { PickScheduleDialog } from './pickScheduleDialog';
import { AlertDialog } from './alertDialog';
import { AgentDialog } from './agentDialog';
import { AgentUtils } from '../agentUtils';
import { JobStepData } from '../data/jobStepData';
const localize = nls.loadMessageBundle();
@@ -110,11 +111,19 @@ export class JobDialog extends AgentDialog<JobData> {
private newAlertButton: sqlops.ButtonComponent;
private isEdit: boolean = false;
// Job objects
private steps: sqlops.AgentJobStepInfo[];
private schedules: sqlops.AgentJobScheduleInfo[];
private alerts: sqlops.AgentAlertInfo[] = [];
constructor(ownerUri: string, jobInfo: sqlops.AgentJobInfo = undefined) {
super(
ownerUri,
new JobData(ownerUri, jobInfo),
jobInfo ? JobDialog.EditDialogTitle : JobDialog.CreateDialogTitle);
this.steps = this.model.jobSteps ? this.model.jobSteps : [];
this.schedules = this.model.jobSchedules ? this.model.jobSchedules : [];
this.alerts = this.model.alerts ? this.model.alerts : [];
this.isEdit = jobInfo ? true : false;
}
@@ -198,12 +207,7 @@ export class JobDialog extends AgentDialog<JobData> {
private initializeStepsTab() {
this.stepsTab.registerContent(async view => {
let previewTag = view.modelBuilder.text()
.withProperties({
value: 'Feature Preview'
}).component();
let steps = this.model.jobSteps ? this.model.jobSteps : [];
let data = this.convertStepsToData(steps);
let data = this.steps ? this.convertStepsToData(this.steps) : [];
this.stepsTable = view.modelBuilder.table()
.withProperties({
columns: [
@@ -237,13 +241,11 @@ export class JobDialog extends AgentDialog<JobData> {
width: 80
}).component();
let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model);
let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, null, true);
stepDialog.onSuccess((step) => {
if (!this.model.jobSteps) {
this.model.jobSteps = [];
}
this.model.jobSteps.push(step);
this.stepsTable.data = this.convertStepsToData(this.model.jobSteps);
let stepInfo = JobStepData.convertToAgentJobStepInfo(step);
this.steps.push(stepInfo);
this.stepsTable.data = this.convertStepsToData(this.steps);
});
this.newStepButton.onDidClick((e)=>{
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
@@ -277,7 +279,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.deleteStepButton.enabled = true;
this.editStepButton.enabled = true;
this.editStepButton.onDidClick(() => {
let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, stepData);
let stepDialog = new JobStepDialog(this.model.ownerUri, '' , this.model, stepData, true);
stepDialog.openDialog();
});
@@ -287,7 +289,6 @@ export class JobDialog extends AgentDialog<JobData> {
agentService.deleteJobStep(this.ownerUri, stepData).then((result) => {
if (result && result.success) {
delete steps[rowNumber];
this.model.jobSteps = steps;
let data = this.convertStepsToData(steps);
this.stepsTable.data = data;
}
@@ -299,10 +300,6 @@ export class JobDialog extends AgentDialog<JobData> {
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
component: previewTag,
title: ''
},
{
component: this.stepsTable,
title: this.JobStepsTopLabelString,
actions: [this.moveStepUpButton, this.moveStepDownButton, this.newStepButton, this.editStepButton, this.deleteStepButton]
@@ -313,10 +310,6 @@ export class JobDialog extends AgentDialog<JobData> {
private initializeAlertsTab() {
this.alertsTab.registerContent(async view => {
let previewTag = view.modelBuilder.text()
.withProperties({
value: 'Feature Preview'
}).component();
let alerts = this.model.alerts ? this.model.alerts : [];
let data = this.convertAlertsToData(alerts);
this.alertsTable = view.modelBuilder.table()
@@ -327,7 +320,7 @@ export class JobDialog extends AgentDialog<JobData> {
this.AlertTypeLabelString
],
data: data,
height: 430,
height: 750,
width: 400
}).component();
@@ -336,18 +329,24 @@ export class JobDialog extends AgentDialog<JobData> {
width: 80
}).component();
this.newAlertButton.onDidClick((e)=>{
let alertDialog = new AlertDialog(this.model.ownerUri, null, []);
alertDialog.onSuccess((dialogModel) => {
});
alertDialog.openDialog();
let alertDialog = new AlertDialog(this.model.ownerUri, this.model, null, true);
alertDialog.onSuccess((alert) => {
let alertInfo = alert.toAgentAlertInfo();
this.alerts.push(alertInfo);
this.alertsTable.data = this.convertAlertsToData(this.alerts);
});
this.newAlertButton.onDidClick(()=>{
if (this.nameTextBox.value && this.nameTextBox.value.length > 0) {
alertDialog.jobId = this.model.jobId;
alertDialog.jobName = this.model.name ? this.model.name : this.nameTextBox.value;
alertDialog.openDialog();
} else {
this.dialog.message = { text: this.BlankJobNameErrorText };
}
});
let formModel = view.modelBuilder.formContainer()
.withFormItems([{
component: previewTag,
title: ''
}, {
component: this.alertsTable,
title: this.AlertsTopLabelString,
actions: [this.newAlertButton]
@@ -380,8 +379,11 @@ export class JobDialog extends AgentDialog<JobData> {
pickScheduleDialog.onSuccess((dialogModel) => {
let selectedSchedule = dialogModel.selectedSchedule;
if (selectedSchedule) {
selectedSchedule.jobName = this.model.name;
this.model.addJobSchedule(selectedSchedule);
let existingSchedule = this.schedules.find(item => item.name === selectedSchedule.name);
if (!existingSchedule) {
selectedSchedule.jobName = this.model.name ? this.model.name : this.nameTextBox.value;
this.schedules.push(selectedSchedule);
}
this.populateScheduleTable();
}
});
@@ -402,8 +404,7 @@ export class JobDialog extends AgentDialog<JobData> {
}
private populateScheduleTable() {
let schedules = this.model.jobSchedules ? this.model.jobSchedules : [];
let data = this.convertSchedulesToData(schedules);
let data = this.convertSchedulesToData(this.schedules);
if (data.length > 0) {
this.schedulesTable.data = data;
this.schedulesTable.height = 750;
@@ -566,5 +567,17 @@ export class JobDialog extends AgentDialog<JobData> {
this.model.pageLevel = this.getActualConditionValue(this.pagerCheckBox, this.pagerConditionDropdown);
this.model.eventLogLevel = this.getActualConditionValue(this.eventLogCheckBox, this.eventLogConditionDropdown);
this.model.deleteLevel = this.getActualConditionValue(this.deleteJobCheckBox, this.deleteJobConditionDropdown);
if (!this.model.jobSteps) {
this.model.jobSteps = [];
}
this.model.jobSteps = this.steps;
if (!this.model.jobSchedules) {
this.model.jobSchedules = [];
}
this.model.jobSchedules = this.schedules;
if (!this.model.alerts) {
this.model.alerts = [];
}
this.model.alerts = this.alerts;
}
}

View File

@@ -118,9 +118,10 @@ export class JobStepDialog extends AgentDialog<JobStepData> {
server: string,
jobModel: JobData,
jobStepInfo?: sqlops.AgentJobStepInfo,
viaJobDialog: boolean = false
) {
super(ownerUri,
jobStepInfo ? JobStepData.convertToJobStepData(jobStepInfo, jobModel) : new JobStepData(ownerUri, jobModel),
jobStepInfo ? JobStepData.convertToJobStepData(jobStepInfo, jobModel) : new JobStepData(ownerUri, jobModel, viaJobDialog),
jobStepInfo ? JobStepDialog.EditDialogTitle : JobStepDialog.NewDialogTitle);
this.stepId = jobStepInfo ?
jobStepInfo.id : jobModel.jobSteps ?

View File

@@ -14,6 +14,7 @@ import { ProxyDialog } from './dialogs/proxyDialog';
import { JobStepDialog } from './dialogs/jobStepDialog';
import { PickScheduleDialog } from './dialogs/pickScheduleDialog';
import { JobData } from './data/jobData';
import { AgentUtils } from './agentUtils';
const localize = nls.loadMessageBundle();
@@ -41,17 +42,23 @@ export class MainController {
let dialog = new JobDialog(ownerUri, jobInfo);
dialog.openDialog();
});
vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobData: JobData, jobStepInfo: sqlops.AgentJobStepInfo) => {
let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo);
dialog.openDialog();
vscode.commands.registerCommand('agent.openNewStepDialog', (ownerUri: string, server: string, jobInfo: sqlops.AgentJobInfo, jobStepInfo: sqlops.AgentJobStepInfo) => {
AgentUtils.getAgentService().then((agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new JobStepDialog(ownerUri, server, jobData, jobStepInfo, false);
dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openPickScheduleDialog', (ownerUri: string, jobName: string) => {
let dialog = new PickScheduleDialog(ownerUri, jobName);
dialog.showDialog();
});
vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, alertInfo: sqlops.AgentAlertInfo, jobs: string[]) => {
let dialog = new AlertDialog(ownerUri, alertInfo, jobs);
dialog.openDialog();
vscode.commands.registerCommand('agent.openAlertDialog', (ownerUri: string, jobInfo: sqlops.AgentJobInfo, alertInfo: sqlops.AgentAlertInfo) => {
AgentUtils.getAgentService().then((agentService) => {
let jobData: JobData = new JobData(ownerUri, jobInfo, agentService);
let dialog = new AlertDialog(ownerUri, jobData, alertInfo, false);
dialog.openDialog();
});
});
vscode.commands.registerCommand('agent.openOperatorDialog', (ownerUri: string, operatorInfo: sqlops.AgentOperatorInfo) => {
let dialog = new OperatorDialog(ownerUri, operatorInfo);

View File

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

View File

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