Agent/proxy ui (#1880)

* finished basic proxy ui

* finished proxy UI and logic

* made changes to accomodate toolsservice side changes
This commit is contained in:
Aditya Bist
2018-07-14 10:43:31 -07:00
committed by Karl Burtram
parent 713c74adfd
commit 74c4b7311e
13 changed files with 225 additions and 28 deletions

View File

@@ -35,6 +35,7 @@ export class ProxyData implements IAgentDialogData {
public async save() { public async save() {
let agentService = await AgentUtils.getAgentService(); let agentService = await AgentUtils.getAgentService();
let result = await agentService.createProxy(this.ownerUri, this.toAgentProxyInfo()); let result = await agentService.createProxy(this.ownerUri, this.toAgentProxyInfo());
console.log(result);
if (!result || !result.success) { if (!result || !result.success) {
// TODO handle error here // TODO handle error here
} }

View File

@@ -15,36 +15,60 @@ const localize = nls.loadMessageBundle();
export class ProxyDialog extends AgentDialog<ProxyData> { export class ProxyDialog extends AgentDialog<ProxyData> {
// Top level // Top level
private static readonly CreateDialogTitle: string = localize('createProxy.createAlert', 'Create Alert'); private static readonly CreateDialogTitle: string = localize('createProxy.createProxy', 'Create Proxy');
private static readonly EditDialogTitle: string = localize('createProxy.createAlert', 'Create Alert'); private static readonly EditDialogTitle: string = localize('createProxy.editProxy', 'Edit Proxy');
private static readonly GeneralTabText: string = localize('createProxy.General', 'General'); private static readonly GeneralTabText: string = localize('createProxy.General', 'General');
// General tab strings // General tab strings
private static readonly ProxyNameTextBoxLabel: string = localize('createProxy.ProxyName', 'Proxy name'); private static readonly ProxyNameTextBoxLabel: string = localize('createProxy.ProxyName', 'Proxy name');
private static readonly CredentialNameTextBoxLabel: string = localize('createProxy.CredentialName', 'Credential name'); private static readonly CredentialNameTextBoxLabel: string = localize('createProxy.CredentialName', 'Credential name');
private static readonly DescriptionTextBoxLabel: string = localize('createProxy.Description', 'Description'); private static readonly DescriptionTextBoxLabel: string = localize('createProxy.Description', 'Description');
private static readonly SubsystemsTableLabel: string = localize('createProxy.Subsystems', 'Subsystems'); private static readonly SubsystemLabel: string = localize('createProxy.SubsystemName', 'Subsystem');
private static readonly SubsystemNameColumnLabel: 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 // UI Components
private generalTab: sqlops.window.modelviewdialog.DialogTab; private generalTab: sqlops.window.modelviewdialog.DialogTab;
// General tab controls // General tab controls
private proxyNameTextBox: sqlops.InputBoxComponent; private proxyNameTextBox: sqlops.InputBoxComponent;
private credentialNameTextBox: sqlops.InputBoxComponent; private credentialNameDropDown: sqlops.DropDownComponent;
private descriptionTextBox: sqlops.InputBoxComponent; 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, proxyInfo: sqlops.AgentProxyInfo = undefined) { private credentials: sqlops.CredentialInfo[];
constructor(ownerUri: string, proxyInfo: sqlops.AgentProxyInfo = undefined, credentials: sqlops.CredentialInfo[]) {
super( super(
ownerUri, ownerUri,
new ProxyData(ownerUri, proxyInfo), new ProxyData(ownerUri, proxyInfo),
proxyInfo ? ProxyDialog.EditDialogTitle : ProxyDialog.CreateDialogTitle); proxyInfo ? ProxyDialog.EditDialogTitle : ProxyDialog.CreateDialogTitle);
this.credentials = credentials;
} }
protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) { protected async initializeDialog(dialog: sqlops.window.modelviewdialog.Dialog) {
this.generalTab = sqlops.window.modelviewdialog.createTab(ProxyDialog.GeneralTabText); this.generalTab = sqlops.window.modelviewdialog.createTab(ProxyDialog.GeneralTabText);
this.initializeGeneralTab(); this.initializeGeneralTab();
this.dialog.content = [this.generalTab]; this.dialog.content = [this.generalTab];
@@ -53,47 +77,143 @@ export class ProxyDialog extends AgentDialog<ProxyData> {
private initializeGeneralTab() { private initializeGeneralTab() {
this.generalTab.registerContent(async view => { 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.credentialNameDropDown = view.modelBuilder.dropDown()
this.descriptionTextBox = view.modelBuilder.inputBox().component();
this.subsystemsTable = view.modelBuilder.table()
.withProperties({ .withProperties({
columns: [ width: 432,
ProxyDialog.SubsystemNameColumnLabel value: '',
], editable: true,
data: [], values: this.credentials.length > 0 ? this.credentials.map(c => c.name) : ['']
height: 500 })
.component();
this.descriptionTextBox = view.modelBuilder.inputBox()
.withProperties({
width: 420,
multiline: true,
height: 300
})
.component();
this.subsystemCheckBox = view.modelBuilder.checkBox()
.withProperties({
label: ProxyDialog.SubsystemLabel
}).component(); }).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() let formModel = view.modelBuilder.formContainer()
.withFormItems([{ .withFormItems([{
component: this.proxyNameTextBox, component: this.proxyNameTextBox,
title: ProxyDialog.ProxyNameTextBoxLabel title: ProxyDialog.ProxyNameTextBoxLabel
}, { }, {
component: this.credentialNameTextBox, component: this.credentialNameDropDown,
title: ProxyDialog.CredentialNameTextBoxLabel title: ProxyDialog.CredentialNameTextBoxLabel
}, { }, {
component: this.descriptionTextBox, component: this.descriptionTextBox,
title: ProxyDialog.DescriptionTextBoxLabel title: ProxyDialog.DescriptionTextBoxLabel
}, { }]).withLayout({ width: 420 }).component();
component: this.subsystemsTable,
title: ProxyDialog.SubsystemsTableLabel
}]).withLayout({ width: '100%' }).component();
await view.initializeModel(formModel); await view.initializeModel(formModel);
this.proxyNameTextBox.value = this.model.accountName; this.proxyNameTextBox.value = this.model.accountName;
this.credentialNameTextBox.value = this.model.credentialName; this.credentialNameDropDown.value = this.model.credentialName;
this.descriptionTextBox.value = this.model.description; this.descriptionTextBox.value = this.model.description;
}); });
} }
protected updateModel() { protected updateModel() {
this.model.accountName = this.proxyNameTextBox.value; 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; this.model.description = this.descriptionTextBox.value;
} }
} }

View File

@@ -47,8 +47,8 @@ export class MainController {
let dialog = new OperatorDialog(ownerUri, operatorInfo); let dialog = new OperatorDialog(ownerUri, operatorInfo);
dialog.openDialog(); dialog.openDialog();
}); });
vscode.commands.registerCommand('agent.openProxyDialog', (ownerUri: string, proxyInfo: sqlops.AgentProxyInfo) => { vscode.commands.registerCommand('agent.openProxyDialog', (ownerUri: string, proxyInfo: sqlops.AgentProxyInfo, credentials: sqlops.CredentialInfo[]) => {
let dialog = new ProxyDialog(ownerUri, proxyInfo); let dialog = new ProxyDialog(ownerUri, proxyInfo, credentials);
dialog.openDialog(); dialog.openDialog();
}); });
} }

View File

@@ -86,6 +86,11 @@ export class TestAgentService implements sqlops.AgentServicesProvider {
return undefined; return undefined;
} }
// Agent Credential method
getCredentials(ownerUri: string): Thenable<sqlops.GetCredentialsResult> {
return undefined;
}
// Job Schedule management methods // Job Schedule management methods
getJobSchedules(ownerUri: string): Thenable<sqlops.AgentJobSchedulesResult> { getJobSchedules(ownerUri: string): Thenable<sqlops.AgentJobSchedulesResult> {
return undefined; return undefined;

View File

@@ -148,6 +148,11 @@ export interface DeleteAgentProxyParams {
proxy: sqlops.AgentProxyInfo; proxy: sqlops.AgentProxyInfo;
} }
// Agent Credentials parameters
export interface GetCredentialsParams {
ownerUri: string;
}
// Job Schedule management parameters // Job Schedule management parameters
export interface AgentJobScheduleParams { export interface AgentJobScheduleParams {
ownerUri: string; ownerUri: string;
@@ -262,6 +267,11 @@ export namespace DeleteAgentProxyRequest {
export const type = new RequestType<DeleteAgentProxyParams, sqlops.ResultStatus, void, void>('agent/deleteproxy'); 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 // Job Schedules requests
export namespace AgentJobSchedulesRequest { export namespace AgentJobSchedulesRequest {
export const type = new RequestType<AgentJobScheduleParams, sqlops.AgentJobSchedulesResult, void, void>('agent/schedules'); export const type = new RequestType<AgentJobScheduleParams, sqlops.AgentJobSchedulesResult, void, void>('agent/schedules');

View File

@@ -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 // Job Schedule management methods
let getJobSchedules = (ownerUri: string): Thenable<sqlops.AgentJobSchedulesResult> => { let getJobSchedules = (ownerUri: string): Thenable<sqlops.AgentJobSchedulesResult> => {
let params: contracts.AgentJobScheduleParams = { let params: contracts.AgentJobScheduleParams = {
@@ -532,6 +548,7 @@ export class AgentServicesFeature extends SqlOpsFeature<undefined> {
createProxy, createProxy,
updateProxy, updateProxy,
deleteProxy, deleteProxy,
getCredentials,
getJobSchedules, getJobSchedules,
createJobSchedule, createJobSchedule,
updateJobSchedule, updateJobSchedule,

View File

@@ -34,6 +34,8 @@ export interface IJobManagementService {
getProxies(connectionUri: string): Thenable<sqlops.AgentProxiesResult>; getProxies(connectionUri: string): Thenable<sqlops.AgentProxiesResult>;
deleteProxy(connectionUri: string, proxy: sqlops.AgentProxyInfo): Thenable<sqlops.ResultStatus>; 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>; jobAction(connectionUri: string, jobName: string, action: string): Thenable<sqlops.ResultStatus>;
addToCache(server: string, cache: JobCacheObject); addToCache(server: string, cache: JobCacheObject);
jobCacheObjectMap: { [server: string]: JobCacheObject; }; jobCacheObjectMap: { [server: string]: JobCacheObject; };

View File

@@ -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> { public getJobHistory(connectionUri: string, jobID: string): Thenable<sqlops.AgentJobHistoryResult> {
return this._runAction(connectionUri, (runner) => { return this._runAction(connectionUri, (runner) => {
return runner.getJobHistory(connectionUri, jobID); return runner.getJobHistory(connectionUri, jobID);

View File

@@ -166,7 +166,11 @@ export class ProxiesViewComponent extends JobManagementView implements OnInit {
public openCreateProxyDialog() { public openCreateProxyDialog() {
let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri; let ownerUri: string = this._commonService.connectionManagementService.connectionInfo.ownerUri;
this._commandService.executeCommand('agent.openProxyDialog', ownerUri); this._jobManagementService.getCredentials(ownerUri).then((result) => {
if (result && result.credentials) {
this._commandService.executeCommand('agent.openProxyDialog', ownerUri, undefined, result.credentials);
}
});
} }
private refreshJobs() { private refreshJobs() {

17
src/sql/sqlops.d.ts vendored
View File

@@ -1503,6 +1503,9 @@ declare module 'sqlops' {
updateProxy(ownerUri: string, originalProxyName: string, proxyInfo: AgentProxyInfo): Thenable<UpdateAgentOperatorResult>; updateProxy(ownerUri: string, originalProxyName: string, proxyInfo: AgentProxyInfo): Thenable<UpdateAgentOperatorResult>;
deleteProxy(ownerUri: string, proxyInfo: AgentProxyInfo): Thenable<ResultStatus>; deleteProxy(ownerUri: string, proxyInfo: AgentProxyInfo): Thenable<ResultStatus>;
// Credential method
getCredentials(ownerUri: string): Thenable<GetCredentialsResult>;
// Job Schedule management methods // Job Schedule management methods
getJobSchedules(ownerUri: string): Thenable<AgentJobSchedulesResult>; getJobSchedules(ownerUri: string): Thenable<AgentJobSchedulesResult>;
createJobSchedule(ownerUri: string, scheduleInfo: AgentJobScheduleInfo): Thenable<CreateAgentJobScheduleResult>; createJobSchedule(ownerUri: string, scheduleInfo: AgentJobScheduleInfo): Thenable<CreateAgentJobScheduleResult>;
@@ -1512,6 +1515,20 @@ declare module 'sqlops' {
registerOnUpdated(handler: () => any): void; 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 ---------------------------------------------------------------------------- // Task service interfaces ----------------------------------------------------------------------------
export enum TaskStatus { export enum TaskStatus {
notStarted = 0, notStarted = 0,

View File

@@ -604,6 +604,13 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
return this._resolveProvider<sqlops.AgentServicesProvider>(handle).deleteProxy(ownerUri, proxy); 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 * SQL Agent job data update notification
*/ */

View File

@@ -366,6 +366,9 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
deleteProxy(connectionUri: string, proxyInfo: sqlops.AgentProxyInfo): Thenable<sqlops.ResultStatus> { deleteProxy(connectionUri: string, proxyInfo: sqlops.AgentProxyInfo): Thenable<sqlops.ResultStatus> {
return self._proxy.$deleteProxy(handle, connectionUri, proxyInfo); return self._proxy.$deleteProxy(handle, connectionUri, proxyInfo);
}, },
getCredentials(connectionUri: string): Thenable<sqlops.GetCredentialsResult> {
return self._proxy.$getCredentials(handle, connectionUri);
}
}); });
return undefined; return undefined;

View File

@@ -372,6 +372,11 @@ export abstract class ExtHostDataProtocolShape {
* Deletes a proxy * Deletes a proxy
*/ */
$deleteProxy(handle: number, connectionUri: string, proxy: sqlops.AgentProxyInfo): Thenable<sqlops.ResultStatus> { throw ni(); } $deleteProxy(handle: number, connectionUri: string, proxy: sqlops.AgentProxyInfo): Thenable<sqlops.ResultStatus> { throw ni(); }
/**
* Get Agent Credentials list
*/
$getCredentials(handle: number, connectionUri: string): Thenable<sqlops.GetCredentialsResult> { throw ni(); }
} }
/** /**