diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts index 9eef374771..1c0a49f17a 100644 --- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts +++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts @@ -242,13 +242,21 @@ function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container: endPointRow.addItem(nameCell, { CSSStyles: { 'width': `${serviceEndpointRowServiceNameCellWidth}px`, 'min-width': `${serviceEndpointRowServiceNameCellWidth}px`, 'text-align': 'center' } }); if (isHyperlink) { const endpointCell = modelBuilder.hyperlink() - .withProperties({ label: endpoint.endpoint, url: endpoint.endpoint, CSSStyles: { 'height': '15px' } }) + .withProperties({ + label: endpoint.endpoint, + title: endpoint.endpoint, + url: endpoint.endpoint, CSSStyles: { 'height': '15px' } + }) .component(); - endPointRow.addItem(endpointCell, { CSSStyles: { 'width': `${serviceEndpointRowEndpointCellWidth}px`, 'min-width': `${serviceEndpointRowEndpointCellWidth}px`, 'overflow': 'hidden', ...cssStyles.hyperlink } }); + endPointRow.addItem(endpointCell, { CSSStyles: { 'width': `${serviceEndpointRowEndpointCellWidth}px`, 'min-width': `${serviceEndpointRowEndpointCellWidth}px`, 'overflow': 'hidden', 'text-overflow': 'ellipsis', ...cssStyles.hyperlink } }); } else if (endpoint.name === Endpoint.sqlServerMaster) { const endpointCell = modelBuilder.text() - .withProperties({ value: endpoint.endpoint, CSSStyles: { ...cssStyles.text, ...cssStyles.hyperlink } }) + .withProperties({ + value: endpoint.endpoint, + title: endpoint.endpoint, + CSSStyles: { 'overflow': 'hidden', 'text-overflow': 'ellipsis', ...cssStyles.text, ...cssStyles.hyperlink } + }) .component(); endpointCell.onDidClick(async () => { const connProfile = bdcModel.getSqlServerMasterConnectionProfile(); @@ -263,20 +271,23 @@ function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container: azdata.connection.openConnectionDialog(undefined, connProfile); } }); - endPointRow.addItem(endpointCell, { CSSStyles: { 'width': `${serviceEndpointRowEndpointCellWidth}px`, 'min-width': `${serviceEndpointRowEndpointCellWidth}px`, 'overflow': 'hidden' } }); + endPointRow.addItem(endpointCell, { CSSStyles: { 'width': `${serviceEndpointRowEndpointCellWidth}px`, 'min-width': `${serviceEndpointRowEndpointCellWidth}px` } }); } else { const endpointCell = modelBuilder.text() - .withProperties({ value: endpoint.endpoint, CSSStyles: { ...cssStyles.text } }) + .withProperties({ + value: endpoint.endpoint, + title: endpoint.endpoint, + CSSStyles: { 'overflow': 'hidden', 'text-overflow': 'ellipsis', ...cssStyles.text } + }) .component(); - endPointRow.addItem(endpointCell, { CSSStyles: { 'width': `${serviceEndpointRowEndpointCellWidth}px`, 'min-width': `${serviceEndpointRowEndpointCellWidth}px`, 'overflow': 'hidden' } }); + endPointRow.addItem(endpointCell, { CSSStyles: { 'width': `${serviceEndpointRowEndpointCellWidth}px`, 'min-width': `${serviceEndpointRowEndpointCellWidth}px` } }); } - const copyValueCell = modelBuilder.button().component(); + const copyValueCell = modelBuilder.button().withProperties({ title: localize('bdc.dashboard.copyTitle', "Copy") }).component(); copyValueCell.iconPath = IconPathHelper.copy; copyValueCell.onDidClick(() => { vscode.env.clipboard.writeText(endpoint.endpoint); }); - copyValueCell.title = localize('bdc.dashboard.copyTitle', "Copy"); copyValueCell.iconHeight = '14px'; copyValueCell.iconWidth = '14px'; endPointRow.addItem(copyValueCell, { CSSStyles: { 'width': '14px', 'min-width': '14px', 'padding-left': '10px', ...cssStyles.text } }); diff --git a/extensions/mssql/src/dashboard/serviceEndpoints.ts b/extensions/mssql/src/dashboard/serviceEndpoints.ts index 6e9b2dfd51..81eceebc66 100644 --- a/extensions/mssql/src/dashboard/serviceEndpoints.ts +++ b/extensions/mssql/src/dashboard/serviceEndpoints.ts @@ -60,16 +60,28 @@ export function registerServiceEndpoints(context: vscode.ExtensionContext): void const container = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'column', width: '100%', height: '100%', alignItems: 'left' }).component(); endpointsArray.forEach(endpointInfo => { - const endPointRow = view.modelBuilder.flexContainer().withLayout({ flexFlow: 'row' }).component(); const nameCell = view.modelBuilder.text().withProperties({ value: endpointInfo.description }).component(); endPointRow.addItem(nameCell, { CSSStyles: { 'width': '35%', 'font-weight': '600', 'user-select': 'text' } }); if (hyperlinkedEndpoints.findIndex(e => e === endpointInfo.serviceName) >= 0) { - const linkCell = view.modelBuilder.hyperlink().withProperties({ label: endpointInfo.endpoint, url: endpointInfo.endpoint }).component(); - endPointRow.addItem(linkCell, { CSSStyles: { 'width': '62%', 'color': '#0078d4', 'text-decoration': 'underline', 'padding-top': '10px' } }); + const linkCell = view.modelBuilder.hyperlink() + .withProperties({ + label: endpointInfo.endpoint, + title: endpointInfo.endpoint, + url: endpointInfo.endpoint + }).component(); + endPointRow.addItem(linkCell, { CSSStyles: { 'width': '62%', 'color': '#0078d4', 'text-decoration': 'underline', 'padding-top': '10px', 'overflow': 'hidden', 'text-overflow': 'ellipsis' } }); } else { - const endpointCell = view.modelBuilder.text().withProperties({ value: endpointInfo.endpoint }).component(); + const endpointCell = + view.modelBuilder.text() + .withProperties( + { + value: endpointInfo.endpoint, + title: endpointInfo.endpoint, + CSSStyles: { 'overflow': 'hidden', 'text-overflow': 'ellipsis' } + }) + .component(); endPointRow.addItem(endpointCell, { CSSStyles: { 'width': '62%', 'user-select': 'text' } }); } const copyValueCell = view.modelBuilder.button().component(); diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts index 8f0472ba00..f4cf77def1 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/pages/serviceSettingsPage.ts @@ -526,7 +526,7 @@ export class ServiceSettingsPage extends WizardPageBase { this.setEnableHadrCheckboxState(Number.parseInt(selectedValue)); })); this.wizard.registerDisposable(enableHadrCheckbox.onChanged(() => { - this.updateReadableSecondaryEndpointComponents(enableHadrCheckbox.checked); + this.updateReadableSecondaryEndpointComponents(!!enableHadrCheckbox.checked); })); } @@ -534,7 +534,7 @@ export class ServiceSettingsPage extends WizardPageBase { // 1. it is ok to enable HADR when there is only 1 replica // 2. if there are multiple replicas, the hadr.enabled switch must be set to true. const enableHadrCheckbox = getCheckboxComponent(VariableNames.EnableHADR_VariableName, this.inputComponents); - const hadrEnabled = sqlInstances === 1 ? enableHadrCheckbox.checked : true; + const hadrEnabled = sqlInstances === 1 ? !!enableHadrCheckbox.checked : true; if (sqlInstances === 1) { enableHadrCheckbox.enabled = true; } else { diff --git a/extensions/resource-deployment/src/ui/modelViewUtils.ts b/extensions/resource-deployment/src/ui/modelViewUtils.ts index cefdc923b3..9a5eee7d58 100644 --- a/extensions/resource-deployment/src/ui/modelViewUtils.ts +++ b/extensions/resource-deployment/src/ui/modelViewUtils.ts @@ -415,15 +415,17 @@ export function setModelValues(inputComponents: InputComponents, model: Model): Object.keys(inputComponents).forEach(key => { let value; const input = inputComponents[key]; - if ('checked' in input) { + if ('checked' in input) { // CheckBoxComponent value = input.checked ? 'true' : 'false'; - } else { + } else if ('value' in input) { // InputBoxComponent or DropDownComponent const inputValue = input.value; if (typeof inputValue === 'string' || typeof inputValue === 'undefined') { value = inputValue; } else { value = inputValue.name; } + } else { + throw new Error(`Unknown input type with ID ${input.id}`); } model.setPropertyValue(key, value); diff --git a/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts b/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts index 5a64484f01..9b3e7709ba 100644 --- a/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts +++ b/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts @@ -236,7 +236,7 @@ export class ResourceTypePickerDialog extends DialogBase { const checkbox = this._view.modelBuilder.checkBox().component(); checkbox.checked = false; this._toDispose.push(checkbox.onChanged(() => { - this._agreementCheckboxChecked = checkbox.checked; + this._agreementCheckboxChecked = !!checkbox.checked; })); const text = this._view.modelBuilder.text().withProperties({ value: agreementInfo.template, diff --git a/src/sql/azdata.d.ts b/src/sql/azdata.d.ts index e0fc74cf3c..62f7ceda79 100644 --- a/src/sql/azdata.d.ts +++ b/src/sql/azdata.d.ts @@ -3062,12 +3062,11 @@ declare module 'azdata' { focused?: boolean; } - export interface TextComponentProperties { + export interface TextComponentProperties extends ComponentProperties, TitledComponentProperties { value?: string; links?: LinkArea[]; description?: string; requiredIndicator?: boolean; - CSSStyles?: { [key: string]: string }; } export interface ImageComponentProperties { @@ -3081,7 +3080,7 @@ declare module 'azdata' { url: string; } - export interface HyperlinkComponentProperties extends ComponentProperties { + export interface HyperlinkComponentProperties extends ComponentProperties, TitledComponentProperties { label: string; url: string; } @@ -3198,6 +3197,13 @@ declare module 'azdata' { clickable?: boolean; } + export interface TitledComponentProperties { + /** + * The title for the component. This title will show when hovered over + */ + title?: string; + } + export interface CardComponent extends Component, CardProperties { onDidActionClick: vscode.Event; onCardSelectedChanged: vscode.Event; @@ -3207,8 +3213,7 @@ declare module 'azdata' { } - export interface TextComponent extends Component, ComponentProperties { - value: string; + export interface TextComponent extends Component, TextComponentProperties { /** * An event called when the text is clicked */ @@ -3232,9 +3237,7 @@ declare module 'azdata' { onDidClick: vscode.Event; } - export interface CheckBoxComponent extends Component { - checked: boolean; - label: string; + export interface CheckBoxComponent extends Component, CheckBoxProperties { onChanged: vscode.Event; } diff --git a/src/sql/sqlops.proposed.d.ts b/src/sql/sqlops.proposed.d.ts index afaabe00b1..c449d3157f 100644 --- a/src/sql/sqlops.proposed.d.ts +++ b/src/sql/sqlops.proposed.d.ts @@ -550,7 +550,7 @@ declare module 'sqlops' { checked?: boolean; } - export interface TextComponentProperties { + export interface TextComponentProperties extends ComponentProperties, TitledComponentProperties { value?: string; links?: LinkArea[]; } @@ -560,7 +560,7 @@ declare module 'sqlops' { url: string; } - export interface HyperlinkComponentProperties extends ComponentProperties { + export interface HyperlinkComponentProperties extends ComponentProperties, TitledComponentProperties { label: string; url: string; } @@ -668,6 +668,13 @@ declare module 'sqlops' { yOffsetChange?: number; } + export interface TitledComponentProperties { + /** + * The title for the component. This title will show when hovered over + */ + title?: string; + } + export interface CardComponent extends Component, CardProperties { onDidActionClick: vscode.Event; onCardSelectedChanged: vscode.Event; @@ -677,8 +684,11 @@ declare module 'sqlops' { } - export interface TextComponent extends Component, ComponentProperties { - value: string; + export interface TextComponent extends Component, TextComponentProperties { + /** + * An event called when the text is clicked + */ + onDidClick: vscode.Event; } export interface HyperlinkComponent extends Component, HyperlinkComponentProperties { @@ -692,9 +702,7 @@ declare module 'sqlops' { onDidClick: vscode.Event; } - export interface CheckBoxComponent extends Component { - checked: boolean; - label: string; + export interface CheckBoxComponent extends Component, CheckBoxProperties { onChanged: vscode.Event; } diff --git a/src/sql/workbench/api/common/extHostModelView.ts b/src/sql/workbench/api/common/extHostModelView.ts index 721cddf2ac..1b6e41dc3f 100644 --- a/src/sql/workbench/api/common/extHostModelView.ts +++ b/src/sql/workbench/api/common/extHostModelView.ts @@ -1119,6 +1119,13 @@ class TextComponentWrapper extends ComponentWrapper implements azdata.TextCompon this.setProperty('value', v); } + public get title(): string { + return this.properties['title']; + } + public set title(title: string) { + this.setProperty('title', title); + } + public get onDidClick(): vscode.Event { let emitter = this._emitterMap.get(ComponentEventType.onDidClick); return emitter && emitter.event; diff --git a/src/sql/workbench/browser/modelComponents/hyperlink.component.ts b/src/sql/workbench/browser/modelComponents/hyperlink.component.ts index 90ef84f918..09a963e139 100644 --- a/src/sql/workbench/browser/modelComponents/hyperlink.component.ts +++ b/src/sql/workbench/browser/modelComponents/hyperlink.component.ts @@ -10,14 +10,14 @@ 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 { TitledComponent } from 'sql/workbench/browser/modelComponents/titledComponent'; @Component({ selector: 'modelview-hyperlink', - template: `{{getLabel()}}` + template: `{{getLabel()}}` }) -export default class HyperlinkComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit { +export default class HyperlinkComponent extends TitledComponent implements IComponent, OnDestroy, AfterViewInit { @Input() descriptor: IComponentDescriptor; @Input() modelStore: IModelStore; diff --git a/src/sql/workbench/browser/modelComponents/interfaces.ts b/src/sql/workbench/browser/modelComponents/interfaces.ts index 0c82ad4a26..450e110208 100644 --- a/src/sql/workbench/browser/modelComponents/interfaces.ts +++ b/src/sql/workbench/browser/modelComponents/interfaces.ts @@ -101,3 +101,7 @@ export interface IModelStore { */ validate(component: IComponent): Thenable; } + +export interface ITitledComponent { + title?: string; +} diff --git a/src/sql/workbench/browser/modelComponents/text.component.ts b/src/sql/workbench/browser/modelComponents/text.component.ts index 42373ae82a..677d8f8c73 100644 --- a/src/sql/workbench/browser/modelComponents/text.component.ts +++ b/src/sql/workbench/browser/modelComponents/text.component.ts @@ -11,22 +11,22 @@ import { import * as azdata from 'azdata'; -import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBase'; import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/workbench/browser/modelComponents/interfaces'; import { SafeHtml, DomSanitizer } from '@angular/platform-browser'; +import { TitledComponent } from 'sql/workbench/browser/modelComponents/titledComponent'; @Component({ selector: 'modelview-text', template: `
-

+

*

` }) -export default class TextComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit { +export default class TextComponent extends TitledComponent implements IComponent, OnDestroy, AfterViewInit { @Input() descriptor: IComponentDescriptor; @Input() modelStore: IModelStore; diff --git a/src/sql/workbench/browser/modelComponents/titledComponent.ts b/src/sql/workbench/browser/modelComponents/titledComponent.ts new file mode 100644 index 0000000000..328c140250 --- /dev/null +++ b/src/sql/workbench/browser/modelComponents/titledComponent.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { + ChangeDetectorRef, ElementRef +} from '@angular/core'; + +import { ITitledComponent } from 'sql/workbench/browser/modelComponents/interfaces'; +import * as azdata from 'azdata'; +import { ComponentBase } from 'sql/workbench/browser/modelComponents/componentBase'; + + +export abstract class TitledComponent extends ComponentBase implements ITitledComponent { + + constructor( + protected _changeRef: ChangeDetectorRef, + protected _el: ElementRef) { + super(_changeRef, _el); + } + + public get title(): string { + return this.getPropertyOrDefault((props) => props.title, ''); + } + + public set title(newTitle: string) { + this.setPropertyFromUI((properties, title) => { properties.title = title; }, newTitle); + } +}