More BDC updates (#6990)

This commit is contained in:
Charles Gagnon
2019-09-04 13:49:08 -07:00
committed by GitHub
parent f05b9396e8
commit 8b5ce753e4
11 changed files with 23 additions and 344 deletions

View File

@@ -10,9 +10,6 @@ import * as vscode from 'vscode';
export enum BdcItemType {
controllerRoot = 'bigDataClusters.itemType.controllerRootNode',
controller = 'bigDataClusters.itemType.controllerNode',
folder = 'bigDataClusters.itemType.folderNode',
sqlMaster = 'bigDataClusters.itemType.sqlMasterNode',
EndPoint = 'bigDataClusters.itemType.endPointNode',
addController = 'bigDataClusters.itemType.addControllerNode',
loadingController = 'bigDataClusters.itemType.loadingControllerNode'
}
@@ -26,8 +23,6 @@ export class IconPathHelper {
private static extensionContext: vscode.ExtensionContext;
public static controllerNode: IconPath;
public static folderNode: IconPath;
public static sqlMasterNode: IconPath;
public static copy: IconPath;
public static refresh: IconPath;
public static status_ok: IconPath;
@@ -40,14 +35,6 @@ export class IconPathHelper {
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/bigDataCluster_controller.svg'),
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/bigDataCluster_controller.svg')
};
IconPathHelper.folderNode = {
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/folder_inverse.svg'),
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/folder.svg')
};
IconPathHelper.sqlMasterNode = {
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/sql_bigdata_cluster_inverse.svg'),
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/sql_bigdata_cluster.svg')
};
IconPathHelper.copy = {
light: IconPathHelper.extensionContext.asAbsolutePath('resources/light/copy.svg'),
dark: IconPathHelper.extensionContext.asAbsolutePath('resources/dark/copy_inverse.svg')

View File

@@ -11,7 +11,6 @@ import { getEndPoints, ControllerError } from '../controller/clusterControllerAp
import { ControllerTreeDataProvider } from '../tree/controllerTreeDataProvider';
import { TreeNode } from '../tree/treeNode';
import { showErrorMessage } from '../utils';
import { EndpointModel } from '../controller/apiGenerated';
const localize = nls.loadMessageBundle();
@@ -22,32 +21,26 @@ export class AddControllerDialogModel {
constructor(
public treeDataProvider: ControllerTreeDataProvider,
public node?: TreeNode,
public prefilledClusterName?: string,
public prefilledUrl?: string,
public prefilledUsername?: string,
public prefilledPassword?: string,
public prefilledRememberPassword?: boolean
) {
this.prefilledClusterName = prefilledClusterName || (node && node['clusterName']);
this.prefilledUrl = prefilledUrl || (node && node['url']);
this.prefilledUsername = prefilledUsername || (node && node['username']);
this.prefilledPassword = prefilledPassword || (node && node['password']);
this.prefilledRememberPassword = prefilledRememberPassword || (node && node['rememberPassword']);
}
public async onComplete(clusterName: string, url: string, username: string, password: string, rememberPassword: boolean): Promise<void> {
public async onComplete(url: string, username: string, password: string, rememberPassword: boolean): Promise<void> {
try {
// We pre-fetch the endpoints here to verify that the information entered is correct (the user is able to connect)
let response = await getEndPoints(url, username, password, true);
if (response && response.endPoints) {
let masterInstance: EndpointModel = undefined;
if (response.endPoints) {
masterInstance = response.endPoints.find(e => e.name && e.name === 'sql-server-master');
}
if (this._canceled) {
return;
}
this.treeDataProvider.addController(clusterName, url, username, password, rememberPassword, masterInstance);
this.treeDataProvider.addController(url, username, password, rememberPassword);
await this.treeDataProvider.saveControllers();
}
} catch (error) {
@@ -76,7 +69,6 @@ export class AddControllerDialog {
private dialog: azdata.window.Dialog;
private uiModelBuilder: azdata.ModelBuilder;
private clusterNameInputBox: azdata.InputBoxComponent;
private urlInputBox: azdata.InputBoxComponent;
private usernameInputBox: azdata.InputBoxComponent;
private passwordInputBox: azdata.InputBoxComponent;
@@ -95,11 +87,6 @@ export class AddControllerDialog {
this.dialog.registerContent(async view => {
this.uiModelBuilder = view.modelBuilder;
this.clusterNameInputBox = this.uiModelBuilder.inputBox()
.withProperties<azdata.InputBoxProperties>({
placeHolder: localize('textClusterNameLower', 'mssql-cluster'),
value: this.model.prefilledUrl || 'mssql-cluster'
}).component();
this.urlInputBox = this.uiModelBuilder.inputBox()
.withProperties<azdata.InputBoxProperties>({
placeHolder: localize('textUrlLower', 'url'),
@@ -127,10 +114,6 @@ export class AddControllerDialog {
.withFormItems([{
components: [
{
component: this.clusterNameInputBox,
title: localize('textClusterNameCapital', 'Cluster Name'),
required: true
}, {
component: this.urlInputBox,
title: localize('textUrlCapital', 'URL'),
required: true
@@ -160,14 +143,13 @@ export class AddControllerDialog {
}
private async validate(): Promise<boolean> {
let clusterName = this.clusterNameInputBox && this.clusterNameInputBox.value;
let url = this.urlInputBox && this.urlInputBox.value;
let username = this.usernameInputBox && this.usernameInputBox.value;
let password = this.passwordInputBox && this.passwordInputBox.value;
let rememberPassword = this.passwordInputBox && !!this.rememberPwCheckBox.checked;
try {
await this.model.onComplete(clusterName, url, username, password, rememberPassword);
await this.model.onComplete(url, username, password, rememberPassword);
return true;
} catch (error) {
showErrorMessage(error);

View File

@@ -22,7 +22,7 @@ export class BdcDashboardModel {
public onDidUpdateEndpoints = this._onDidUpdateEndpoints.event;
public onDidUpdateBdcStatus = this._onDidUpdateBdcStatus.event;
constructor(public clusterName: string, private url: string, private username: string, private password: string) {
constructor(private url: string, private username: string, private password: string) {
this.refresh();
}
@@ -72,7 +72,7 @@ export class BdcDashboardModel {
// We default to sa - if that doesn't work then callers of this should open up a connection
// dialog so the user can enter in the correct connection information
return {
connectionName: '',
connectionName: undefined,
serverName: sqlServerMasterEndpoint.endpoint,
databaseName: undefined,
userName: 'sa',

View File

@@ -65,32 +65,22 @@ export class BdcDashboardOverviewPage {
// Row 1
const row1 = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row', height: '30px', alignItems: 'center' }).component();
// Cluster Name
const clusterNameLabel = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.clusterName', "Cluster Name :") }).component();
const clusterNameValue = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: this.model.clusterName }).component();
row1.addItem(clusterNameLabel, { CSSStyles: { 'width': '100px', 'min-width': '100px', 'user-select': 'none', 'font-weight': 'bold' } });
row1.addItem(clusterNameValue, { CSSStyles: { 'user-select': 'text' } });
rootContainer.addItem(row1, { CSSStyles: { 'padding-left': '10px', 'border-top': 'solid 1px #ccc', 'box-sizing': 'border-box', 'user-select': 'text' } });
// Row 2
const row2 = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row', height: '30px', alignItems: 'center' }).component();
// Cluster State
const clusterStateLabel = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.clusterState', "Cluster State :") }).component();
const clusterStateValue = view.modelBuilder.text().withProperties({ CSSStyles: { 'user-select': 'text' } }).component();
this.clusterStateLoadingComponent = view.modelBuilder.loadingComponent().withItem(clusterStateValue).component();
row2.addItem(clusterStateLabel, { CSSStyles: { 'width': '125px', 'min-width': '125px', 'user-select': 'none', 'font-weight': 'bold' } });
row2.addItem(this.clusterStateLoadingComponent, { CSSStyles: { 'width': '125px', 'min-width': '125px', 'user-select': 'none' } });
row1.addItem(clusterStateLabel, { CSSStyles: { 'width': '125px', 'min-width': '125px', 'user-select': 'none', 'font-weight': 'bold' } });
row1.addItem(this.clusterStateLoadingComponent, { CSSStyles: { 'width': '125px', 'min-width': '125px', 'user-select': 'none' } });
// Health Status
const healthStatusLabel = view.modelBuilder.text().withProperties<azdata.TextComponentProperties>({ value: localize('bdc.dashboard.healthStatus', "Health Status :") }).component();
const healthStatusValue = view.modelBuilder.text().withProperties({ CSSStyles: { 'user-select': 'text' } }).component();
this.clusterHealthStatusLoadingComponent = view.modelBuilder.loadingComponent().withItem(healthStatusValue).component();
row2.addItem(healthStatusLabel, { CSSStyles: { 'width': '125px', 'min-width': '125px', 'user-select': 'none', 'font-weight': 'bold' } });
row2.addItem(this.clusterHealthStatusLoadingComponent, { CSSStyles: { 'width': '125px', 'min-width': '125px', 'user-select': 'none' } });
row1.addItem(healthStatusLabel, { CSSStyles: { 'width': '125px', 'min-width': '125px', 'user-select': 'none', 'font-weight': 'bold' } });
row1.addItem(this.clusterHealthStatusLoadingComponent, { CSSStyles: { 'width': '125px', 'min-width': '125px', 'user-select': 'none' } });
rootContainer.addItem(row2, { CSSStyles: { 'padding-left': '10px', 'border-bottom': 'solid 1px #ccc', 'box-sizing': 'border-box', 'user-select': 'text' } });
rootContainer.addItem(row1, { CSSStyles: { 'padding-left': '10px', 'border-bottom': 'solid 1px #ccc', 'box-sizing': 'border-box', 'user-select': 'text' } });
// ############
// # OVERVIEW #

View File

@@ -13,12 +13,10 @@ import { AddControllerNode } from './addControllerNode';
import { ControllerRootNode, ControllerNode } from './controllerTreeNode';
import { showErrorMessage } from '../utils';
import { LoadingControllerNode } from './loadingControllerNode';
import { EndpointModel } from '../controller/apiGenerated';
const CredentialNamespace = 'clusterControllerCredentials';
interface IControllerInfoSlim {
clusterName: string;
url: string;
username: string;
password?: string;
@@ -58,15 +56,13 @@ export class ControllerTreeDataProvider implements vscode.TreeDataProvider<TreeN
}
public addController(
clusterName: string,
url: string,
username: string,
password: string,
rememberPassword: boolean,
masterInstance?: EndpointModel
rememberPassword: boolean
): void {
this.removeNonControllerNodes();
this.root.addControllerNode(clusterName, url, username, password, rememberPassword, masterInstance);
this.root.addControllerNode(url, username, password, rememberPassword);
this.notifyNodeChanged();
}
@@ -120,7 +116,7 @@ export class ControllerTreeDataProvider implements vscode.TreeDataProvider<TreeN
password = await this.getPassword(c.url, c.username);
}
this.root.addChild(new ControllerNode(
c.clusterName, c.url, c.username, password, c.rememberPassword,
c.url, c.username, password, c.rememberPassword,
undefined, this.root, this, undefined
));
}
@@ -135,10 +131,9 @@ export class ControllerTreeDataProvider implements vscode.TreeDataProvider<TreeN
}
public async saveControllers(): Promise<void> {
let controllers = this.root.children.map(e => {
let controllers = this.root.children.map((e): IControllerInfoSlim => {
let controller = e as ControllerNode;
return <IControllerInfoSlim>{
clusterName: controller.clusterName,
return {
url: controller.url,
username: controller.username,
password: controller.password,
@@ -146,9 +141,8 @@ export class ControllerTreeDataProvider implements vscode.TreeDataProvider<TreeN
};
});
let controllersWithoutPassword = controllers.map(e => {
return <IControllerInfoSlim>{
clusterName: e.clusterName,
let controllersWithoutPassword = controllers.map((e): IControllerInfoSlim => {
return {
url: e.url,
username: e.username,
rememberPassword: e.rememberPassword

View File

@@ -11,9 +11,6 @@ import * as nls from 'vscode-nls';
import { IControllerTreeChangeHandler } from './controllerTreeChangeHandler';
import { TreeNode } from './treeNode';
import { IconPathHelper, BdcItemType, IconPath } from '../constants';
import { getEndPoints } from '../controller/clusterControllerApi';
import { showErrorMessage } from '../utils';
import { EndpointModel } from '../controller/apiGenerated';
const localize = nls.loadMessageBundle();
@@ -44,9 +41,7 @@ export abstract class ControllerTreeNode extends TreeNode {
let item: vscode.TreeItem = {};
item.id = this.id;
item.label = this.label;
item.collapsibleState = this.isLeaf ?
vscode.TreeItemCollapsibleState.None :
vscode.TreeItemCollapsibleState.Collapsed;
item.collapsibleState = vscode.TreeItemCollapsibleState.None;
item.iconPath = this._iconPath;
item.contextValue = this._nodeType;
item.tooltip = this._description;
@@ -103,23 +98,19 @@ export abstract class ControllerTreeNode extends TreeNode {
export class ControllerRootNode extends ControllerTreeNode {
private _masterNodeFactory: SqlMasterNodeFactory;
constructor(treeChangeHandler: IControllerTreeChangeHandler) {
super('root', undefined, treeChangeHandler, undefined, BdcItemType.controllerRoot);
this._masterNodeFactory = new SqlMasterNodeFactory();
}
public async getChildren(): Promise<ControllerNode[]> {
return this.children as ControllerNode[];
}
public addControllerNode(clusterName: string,
public addControllerNode(
url: string,
username: string,
password: string,
rememberPassword: boolean,
masterInstance?: EndpointModel
rememberPassword: boolean
): void {
let controllerNode = this.getExistingControllerNode(url, username);
if (controllerNode) {
@@ -127,13 +118,9 @@ export class ControllerRootNode extends ControllerTreeNode {
controllerNode.rememberPassword = rememberPassword;
controllerNode.clearChildren();
} else {
controllerNode = new ControllerNode(clusterName, url, username, password, rememberPassword, undefined, this, this.treeChangeHandler, undefined);
controllerNode = new ControllerNode(url, username, password, rememberPassword, undefined, this, this.treeChangeHandler, undefined);
this.addChild(controllerNode);
}
if (masterInstance) {
controllerNode.addSqlMasterNode(masterInstance.endpoint, masterInstance.description);
}
}
public deleteControllerNode(url: string, username: string): ControllerNode {
@@ -156,16 +143,11 @@ export class ControllerRootNode extends ControllerTreeNode {
let nodes = this.children as ControllerNode[];
return nodes.find(e => e.url === url && e.username === username);
}
public get sqlMasterNodeFactory(): SqlMasterNodeFactory {
return this._masterNodeFactory;
}
}
export class ControllerNode extends ControllerTreeNode {
constructor(
private _clusterName: string,
private _url: string,
private _username: string,
private _password: string,
@@ -178,7 +160,6 @@ export class ControllerNode extends ControllerTreeNode {
super(label, parent, treeChangeHandler, description, BdcItemType.controller, IconPathHelper.controllerNode);
this.label = label;
this.description = description;
}
public async getChildren(): Promise<ControllerTreeNode[]> {
@@ -190,18 +171,6 @@ export class ControllerNode extends ControllerTreeNode {
vscode.commands.executeCommand('bigDataClusters.command.addController', this);
return this.children as ControllerTreeNode[];
}
try {
let response = await getEndPoints(this._url, this._username, this._password, true);
if (response && response.endPoints) {
let master = response.endPoints.find(e => e.name && e.name === 'sql-server-master');
this.addSqlMasterNode(master.endpoint, master.description);
}
return this.children as ControllerTreeNode[];
} catch (error) {
showErrorMessage(error);
return this.children as ControllerTreeNode[];
}
}
public static toIpAndPort(url: string): string {
@@ -211,37 +180,6 @@ export class ControllerNode extends ControllerTreeNode {
return url.trim().replace(/ /g, '').replace(/^.+\:\/\//, '').replace(/:(\d+)$/, ',$1');
}
public addSqlMasterNode(endPointAddress: string, description: string): void {
let epFolder = this.getEndPointFolderNode();
let node = (this.root as ControllerRootNode).sqlMasterNodeFactory
.getSqlMasterNode(endPointAddress, epFolder, undefined, this.treeChangeHandler, description);
epFolder.addChild(node);
}
private getEndPointFolderNode(): FolderNode {
let label = localize('textSqlServers', 'SQL Servers');
let epFolderNode = this.children.find(e => e instanceof FolderNode && e.label === label);
if (!epFolderNode) {
epFolderNode = new FolderNode(label, this, this.treeChangeHandler);
this.addChild(epFolderNode);
}
return epFolderNode as FolderNode;
}
public getTreeItem(): vscode.TreeItem {
let item: vscode.TreeItem = super.getTreeItem();
item.collapsibleState = vscode.TreeItemCollapsibleState.Collapsed;
return item;
}
public get clusterName() {
return this._clusterName;
}
public set clusterName(clusterName: string) {
this._clusterName = clusterName;
}
public get url() {
return this._url;
}
@@ -291,122 +229,3 @@ export class ControllerNode extends ControllerTreeNode {
}
}
export class FolderNode extends ControllerTreeNode {
constructor(
label: string,
parent: ControllerTreeNode,
treeChangeHandler: IControllerTreeChangeHandler
) {
super(label, parent, treeChangeHandler, label, BdcItemType.folder, IconPathHelper.folderNode);
}
}
export class SqlMasterNode extends ControllerTreeNode {
private static readonly _role: string = 'sql-server-master';
private _username: string;
private _password: string;
constructor(
private _endPointAddress: string,
parent: ControllerTreeNode,
label: string,
treeChangeHandler: IControllerTreeChangeHandler,
description?: string,
) {
super(label, parent, treeChangeHandler, description, BdcItemType.sqlMaster, IconPathHelper.sqlMasterNode);
this._username = 'sa';
this.label = label;
this.description = description;
}
private getControllerPassword(): string {
if (!this._password) {
let current: TreeNode = this;
while (current && !(current instanceof ControllerNode)) {
current = current.parent;
}
this._password = current && current instanceof ControllerNode ? current.password : undefined;
}
return this._password;
}
public getTreeItem(): vscode.TreeItem {
let item = super.getTreeItem();
let connectionProfile: azdata.IConnectionProfile = {
id: this.id,
connectionName: '',
serverName: this._endPointAddress,
databaseName: '',
userName: this._username,
password: this.getControllerPassword(),
authenticationType: 'SqlLogin',
savePassword: false,
groupFullName: '',
groupId: '',
providerName: 'MSSQL',
saveProfile: false,
options: {}
};
return Object.assign(item, {
payload: connectionProfile,
childProvider: 'MSSQL',
type: 'Server'
});
}
public get role() {
return SqlMasterNode._role;
}
public get endPointAddress() {
return this._endPointAddress;
}
public set endPointAddress(endPointAddress: string) {
this._endPointAddress = endPointAddress;
}
public set label(label: string) {
super.label = label || `master: ${this._endPointAddress} (${this._username})`;
}
public get label(): string {
return super.label;
}
public set description(description: string) {
super.description = description || super.label;
}
public get description(): string {
return super.description;
}
}
export class SqlMasterNodeFactory {
private registry: {} = {};
public getSqlMasterNode(
endPointAddress: string,
parent: ControllerTreeNode,
label: string,
treeChangeHandler: IControllerTreeChangeHandler,
description?: string
): SqlMasterNode {
let id = this.createRegistryId(endPointAddress, 'sa');
if (!this.registry[id]) {
this.registry[id] = new SqlMasterNode(endPointAddress, parent, label, treeChangeHandler, description);
} else {
let node = this.registry[id] as SqlMasterNode;
node.parent = parent;
node.label = label;
node.treeChangeHandler = treeChangeHandler;
description = description;
}
return this.registry[id] as SqlMasterNode;
}
private createRegistryId(endPointAddress: string, username: string): string {
return `${endPointAddress}::${username}`;
}
}