diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardModel.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardModel.ts index 9bced1ced0..ad193a1c4f 100644 --- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardModel.ts +++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardModel.ts @@ -5,6 +5,7 @@ 'use strict'; +import * as azdata from 'azdata'; import * as vscode from 'vscode'; import { getBdcStatus, getEndPoints } from '../controller/clusterControllerApi'; import { EndpointModel, BdcStatusModel } from '../controller/apiGenerated'; @@ -56,6 +57,36 @@ export class BdcDashboardModel { }) ]).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: {} + }; + } } /** diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts index 0e47bf4628..3469ed7737 100644 --- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts +++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts @@ -213,7 +213,7 @@ export class BdcDashboardOverviewPage { this.endpointsRowContainer.clearItems(); 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' } }); } -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 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' } }); @@ -250,6 +250,25 @@ function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container: .component(); 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 { const endpointCell = modelBuilder.text() .withProperties({ value: endpoint.endpoint, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } }) diff --git a/src/sql/azdata.d.ts b/src/sql/azdata.d.ts index ce6b0d5fdf..1f920f412c 100644 --- a/src/sql/azdata.d.ts +++ b/src/sql/azdata.d.ts @@ -3106,6 +3106,10 @@ declare module 'azdata' { export interface TextComponent extends Component, ComponentProperties { value: string; + /** + * An event called when the text is clicked + */ + onDidClick: vscode.Event; } export interface HyperlinkComponent extends Component, HyperlinkComponentProperties { @@ -3118,6 +3122,9 @@ declare module 'azdata' { } export interface RadioButtonComponent extends Component, RadioButtonProperties { + /** + * An event called when the radio button is clicked + */ onDidClick: vscode.Event; } diff --git a/src/sql/workbench/api/common/extHostModelView.ts b/src/sql/workbench/api/common/extHostModelView.ts index be0cbe6f67..b636a5d771 100644 --- a/src/sql/workbench/api/common/extHostModelView.ts +++ b/src/sql/workbench/api/common/extHostModelView.ts @@ -693,7 +693,6 @@ class CardWrapper extends ComponentWrapper implements azdata.CardComponent { super(proxy, handle, ModelComponentTypes.Card, id); this.properties = {}; this._emitterMap.set(ComponentEventType.onDidClick, new Emitter()); - this._emitterMap.set(ComponentEventType.onDidClick, new Emitter()); } public get label(): string { @@ -1103,6 +1102,7 @@ class TextComponentWrapper extends ComponentWrapper implements azdata.TextCompon constructor(proxy: MainThreadModelViewShape, handle: number, id: string) { super(proxy, handle, ModelComponentTypes.Text, id); this.properties = {}; + this._emitterMap.set(ComponentEventType.onDidClick, new Emitter()); } public get value(): string { @@ -1111,6 +1111,11 @@ class TextComponentWrapper extends ComponentWrapper implements azdata.TextCompon public set value(v: string) { this.setProperty('value', v); } + + public get onDidClick(): vscode.Event { + let emitter = this._emitterMap.get(ComponentEventType.onDidClick); + return emitter && emitter.event; + } } class TableComponentWrapper extends ComponentWrapper implements azdata.TableComponent { diff --git a/src/sql/workbench/browser/modelComponents/text.component.ts b/src/sql/workbench/browser/modelComponents/text.component.ts index 6f4159de2d..e7598bea54 100644 --- a/src/sql/workbench/browser/modelComponents/text.component.ts +++ b/src/sql/workbench/browser/modelComponents/text.component.ts @@ -12,13 +12,13 @@ import { import * as azdata from 'azdata'; 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'; @Component({ selector: 'modelview-text', template: ` -

` +

` }) export default class TextComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit { @Input() descriptor: IComponentDescriptor; @@ -69,4 +69,11 @@ export default class TextComponent extends ComponentBase implements IComponent, } return text; } + + private onClick() { + this.fireEvent({ + eventType: ComponentEventType.onDidClick, + args: undefined + }); + } }