Make sql master link clickable that opens connection (#6982)

* Make sql master link clickable that opens connection

* Improve comments and fix break

* Show error message if failed to connect and clear username

* Remove key handler - text doesn't even get focus currently so this isn't doing anything
This commit is contained in:
Charles Gagnon
2019-08-27 17:39:05 -07:00
committed by GitHub
parent 4e25bc9396
commit 99350210d7
5 changed files with 74 additions and 5 deletions

View File

@@ -5,6 +5,7 @@
'use strict'; 'use strict';
import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { getBdcStatus, getEndPoints } from '../controller/clusterControllerApi'; import { getBdcStatus, getEndPoints } from '../controller/clusterControllerApi';
import { EndpointModel, BdcStatusModel } from '../controller/apiGenerated'; import { EndpointModel, BdcStatusModel } from '../controller/apiGenerated';
@@ -56,6 +57,36 @@ export class BdcDashboardModel {
}) })
]).catch(error => showErrorMessage(error)); ]).catch(error => showErrorMessage(error));
} }
/**
* Gets a partially filled connection profile for the SQL Server Master Instance endpoint
* associated with this cluster.
* @returns The IConnectionProfile - or undefined if the endpoints haven't been loaded yet
*/
public getSqlServerMasterConnectionProfile(): azdata.IConnectionProfile | undefined {
const sqlServerMasterEndpoint = this.serviceEndpoints.find(e => e.name === Endpoint.sqlServerMaster);
if (!sqlServerMasterEndpoint) {
return undefined;
}
// 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: '',
serverName: sqlServerMasterEndpoint.endpoint,
databaseName: undefined,
userName: 'sa',
password: this.password,
authenticationType: '',
savePassword: true,
groupFullName: undefined,
groupId: undefined,
providerName: 'MSSQL',
saveProfile: true,
id: undefined,
options: {}
};
}
} }
/** /**

View File

@@ -213,7 +213,7 @@ export class BdcDashboardOverviewPage {
this.endpointsRowContainer.clearItems(); this.endpointsRowContainer.clearItems();
endpoints.forEach((e, i) => { endpoints.forEach((e, i) => {
createServiceEndpointRow(this.modelBuilder, this.endpointsRowContainer, e, hyperlinkedEndpoints.some(he => he === e.name), i === endpoints.length - 1); createServiceEndpointRow(this.modelBuilder, this.endpointsRowContainer, e, this.model, hyperlinkedEndpoints.some(he => he === e.name), i === endpoints.length - 1);
}); });
} }
} }
@@ -240,7 +240,7 @@ function createServiceStatusRow(modelBuilder: azdata.ModelBuilder, container: az
container.addItem(serviceStatusRow, { CSSStyles: { 'padding-left': '10px', 'border-top': 'solid 1px #ccc', 'border-bottom': isLastRow ? 'solid 1px #ccc' : '', 'box-sizing': 'border-box', 'user-select': 'text' } }); container.addItem(serviceStatusRow, { CSSStyles: { 'padding-left': '10px', 'border-top': 'solid 1px #ccc', 'border-bottom': isLastRow ? 'solid 1px #ccc' : '', 'box-sizing': 'border-box', 'user-select': 'text' } });
} }
function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container: azdata.FlexContainer, endpoint: EndpointModel, isHyperlink: boolean, isLastRow: boolean): void { function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container: azdata.FlexContainer, endpoint: EndpointModel, bdcModel: BdcDashboardModel, isHyperlink: boolean, isLastRow: boolean): void {
const endPointRow = modelBuilder.flexContainer().withLayout({ flexFlow: 'row', alignItems: 'center', height: '40px' }).component(); const endPointRow = modelBuilder.flexContainer().withLayout({ flexFlow: 'row', alignItems: 'center', height: '40px' }).component();
const nameCell = modelBuilder.text().withProperties({ value: getEndpointDisplayText(endpoint.name, endpoint.description), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' } }).component(); const nameCell = modelBuilder.text().withProperties({ value: getEndpointDisplayText(endpoint.name, endpoint.description), CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' } }).component();
endPointRow.addItem(nameCell, { CSSStyles: { 'width': serviceEndpointRowServiceNameCellWidth, 'min-width': serviceEndpointRowServiceNameCellWidth, 'user-select': 'text', 'text-align': 'center' } }); endPointRow.addItem(nameCell, { CSSStyles: { 'width': serviceEndpointRowServiceNameCellWidth, 'min-width': serviceEndpointRowServiceNameCellWidth, 'user-select': 'text', 'text-align': 'center' } });
@@ -250,6 +250,25 @@ function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container:
.component(); .component();
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'color': '#0078d4', 'text-decoration': 'underline', 'overflow': 'hidden', 'padding-left': '10px' } }); endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'color': '#0078d4', 'text-decoration': 'underline', 'overflow': 'hidden', 'padding-left': '10px' } });
} }
else if (endpoint.name === Endpoint.sqlServerMaster) {
const endpointCell = modelBuilder.text()
.withProperties({ value: endpoint.endpoint, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text', 'cursor': 'pointer', 'color': '#0078d4', 'text-decoration': 'underline' } })
.component();
endpointCell.onDidClick(async () => {
const connProfile = bdcModel.getSqlServerMasterConnectionProfile();
const result = await azdata.connection.connect(connProfile, true, true);
if (!result.connected) {
if (result.errorMessage && result.errorMessage.length > 0) {
vscode.window.showErrorMessage(result.errorMessage);
}
// Clear out the password and username before connecting since those being wrong are likely the issue
connProfile.userName = undefined;
connProfile.password = undefined;
azdata.connection.openConnectionDialog(undefined, connProfile);
}
});
endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'overflow': 'hidden', 'padding-left': '10px' } });
}
else { else {
const endpointCell = modelBuilder.text() const endpointCell = modelBuilder.text()
.withProperties({ value: endpoint.endpoint, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } }) .withProperties({ value: endpoint.endpoint, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } })

7
src/sql/azdata.d.ts vendored
View File

@@ -3106,6 +3106,10 @@ declare module 'azdata' {
export interface TextComponent extends Component, ComponentProperties { export interface TextComponent extends Component, ComponentProperties {
value: string; value: string;
/**
* An event called when the text is clicked
*/
onDidClick: vscode.Event<any>;
} }
export interface HyperlinkComponent extends Component, HyperlinkComponentProperties { export interface HyperlinkComponent extends Component, HyperlinkComponentProperties {
@@ -3118,6 +3122,9 @@ declare module 'azdata' {
} }
export interface RadioButtonComponent extends Component, RadioButtonProperties { export interface RadioButtonComponent extends Component, RadioButtonProperties {
/**
* An event called when the radio button is clicked
*/
onDidClick: vscode.Event<any>; onDidClick: vscode.Event<any>;
} }

View File

@@ -693,7 +693,6 @@ class CardWrapper extends ComponentWrapper implements azdata.CardComponent {
super(proxy, handle, ModelComponentTypes.Card, id); super(proxy, handle, ModelComponentTypes.Card, id);
this.properties = {}; this.properties = {};
this._emitterMap.set(ComponentEventType.onDidClick, new Emitter<any>()); this._emitterMap.set(ComponentEventType.onDidClick, new Emitter<any>());
this._emitterMap.set(ComponentEventType.onDidClick, new Emitter<any>());
} }
public get label(): string { public get label(): string {
@@ -1103,6 +1102,7 @@ class TextComponentWrapper extends ComponentWrapper implements azdata.TextCompon
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) { constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
super(proxy, handle, ModelComponentTypes.Text, id); super(proxy, handle, ModelComponentTypes.Text, id);
this.properties = {}; this.properties = {};
this._emitterMap.set(ComponentEventType.onDidClick, new Emitter<any>());
} }
public get value(): string { public get value(): string {
@@ -1111,6 +1111,11 @@ class TextComponentWrapper extends ComponentWrapper implements azdata.TextCompon
public set value(v: string) { public set value(v: string) {
this.setProperty('value', v); this.setProperty('value', v);
} }
public get onDidClick(): vscode.Event<any> {
let emitter = this._emitterMap.get(ComponentEventType.onDidClick);
return emitter && emitter.event;
}
} }
class TableComponentWrapper extends ComponentWrapper implements azdata.TableComponent { class TableComponentWrapper extends ComponentWrapper implements azdata.TableComponent {

View File

@@ -12,13 +12,13 @@ import {
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBase'; import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBase';
import { IComponent, IComponentDescriptor, IModelStore } from 'sql/workbench/browser/modelComponents/interfaces'; import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/workbench/browser/modelComponents/interfaces';
import { SafeHtml, DomSanitizer } from '@angular/platform-browser'; import { SafeHtml, DomSanitizer } from '@angular/platform-browser';
@Component({ @Component({
selector: 'modelview-text', selector: 'modelview-text',
template: ` template: `
<p [style.width]="getWidth()" [innerHTML]="getValue()" [ngStyle]="this.CSSStyles"></p>` <p [style.width]="getWidth()" [innerHTML]="getValue()" [ngStyle]="this.CSSStyles" (click)="onClick()"></p>`
}) })
export default class TextComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit { export default class TextComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
@Input() descriptor: IComponentDescriptor; @Input() descriptor: IComponentDescriptor;
@@ -69,4 +69,11 @@ export default class TextComponent extends ComponentBase implements IComponent,
} }
return text; return text;
} }
private onClick() {
this.fireEvent({
eventType: ComponentEventType.onDidClick,
args: undefined
});
}
} }