diff --git a/extensions/big-data-cluster/src/bigDataCluster/constants.ts b/extensions/big-data-cluster/src/bigDataCluster/constants.ts index 7cab730ced..fa19792274 100644 --- a/extensions/big-data-cluster/src/bigDataCluster/constants.ts +++ b/extensions/big-data-cluster/src/bigDataCluster/constants.ts @@ -70,3 +70,8 @@ export class IconPathHelper { }; } } + +export namespace cssStyles { + export const hyperlink = { 'user-select': 'text', 'color': '#0078d4', 'text-decoration': 'underline', 'cursor': 'pointer' }; + export const text = { 'margin-block-start': '0px', 'margin-block-end': '0px' }; +} diff --git a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts index 17e661ac81..d2fd835dcb 100644 --- a/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts +++ b/extensions/big-data-cluster/src/bigDataCluster/dialog/bdcDashboardOverviewPage.ts @@ -9,7 +9,7 @@ import * as azdata from 'azdata'; import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { BdcDashboardModel } from './bdcDashboardModel'; -import { IconPathHelper } from '../constants'; +import { IconPathHelper, cssStyles } from '../constants'; import { getStateDisplayText, getHealthStatusDisplayText, getEndpointDisplayText, getHealthStatusIcon, getServiceNameDisplayText, Endpoint } from '../utils'; import { EndpointModel, ServiceStatusModel, BdcStatusModel } from '../controller/apiGenerated'; import { BdcDashboard } from './bdcDashboard'; @@ -250,13 +250,21 @@ function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container: endPointRow.addItem(nameCell, { CSSStyles: { 'width': serviceEndpointRowServiceNameCellWidth, 'min-width': serviceEndpointRowServiceNameCellWidth, 'user-select': 'text', '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, 'min-width': serviceEndpointRowEndpointCellWidth, 'color': '#0078d4', 'text-decoration': 'underline', 'overflow': 'hidden', 'padding-left': '10px' } }); + endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'overflow': 'hidden', 'text-overflow': 'ellipsis', ...cssStyles.hyperlink } }); } 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' } }) + .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(); @@ -271,13 +279,17 @@ function createServiceEndpointRow(modelBuilder: azdata.ModelBuilder, container: azdata.connection.openConnectionDialog(undefined, connProfile); } }); - endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'overflow': 'hidden', 'padding-left': '10px' } }); + endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth } }); } else { const endpointCell = modelBuilder.text() - .withProperties({ value: endpoint.endpoint, CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px', 'user-select': 'text' } }) + .withProperties({ + value: endpoint.endpoint, + title: endpoint.endpoint, + CSSStyles: { 'overflow': 'hidden', 'text-overflow': 'ellipsis', ...cssStyles.text } + }) .component(); - endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth, 'overflow': 'hidden', 'padding-left': '10px' } }); + endPointRow.addItem(endpointCell, { CSSStyles: { 'width': serviceEndpointRowEndpointCellWidth, 'min-width': serviceEndpointRowEndpointCellWidth } }); } const copyValueCell = modelBuilder.button().component(); copyValueCell.iconPath = IconPathHelper.copy; 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/src/sql/azdata.d.ts b/src/sql/azdata.d.ts index 2e896776d8..b12731ab5c 100644 --- a/src/sql/azdata.d.ts +++ b/src/sql/azdata.d.ts @@ -3051,10 +3051,9 @@ declare module 'azdata' { focused?: boolean; } - export interface TextComponentProperties { + export interface TextComponentProperties extends ComponentProperties, TitledComponentProperties { value?: string; links?: LinkArea[]; - CSSStyles?: { [key: string]: string }; } export interface LinkArea { @@ -3062,7 +3061,7 @@ declare module 'azdata' { url: string; } - export interface HyperlinkComponentProperties extends ComponentProperties { + export interface HyperlinkComponentProperties extends ComponentProperties, TitledComponentProperties { label: string; url: string; } @@ -3165,6 +3164,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; @@ -3174,8 +3180,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 */ @@ -3183,8 +3188,6 @@ declare module 'azdata' { } export interface HyperlinkComponent extends Component, HyperlinkComponentProperties { - label: string; - url: string; } export interface InputBoxComponent extends Component, InputBoxProperties { diff --git a/src/sql/sqlops.proposed.d.ts b/src/sql/sqlops.proposed.d.ts index a23600d50d..19ac91d696 100644 --- a/src/sql/sqlops.proposed.d.ts +++ b/src/sql/sqlops.proposed.d.ts @@ -545,7 +545,7 @@ declare module 'sqlops' { checked?: boolean; } - export interface TextComponentProperties { + export interface TextComponentProperties extends ComponentProperties, TitledComponentProperties { value?: string; links?: LinkArea[]; } @@ -555,7 +555,7 @@ declare module 'sqlops' { url: string; } - export interface HyperlinkComponentProperties extends ComponentProperties { + export interface HyperlinkComponentProperties extends ComponentProperties, TitledComponentProperties { label: string; url: string; } @@ -651,6 +651,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; @@ -660,13 +667,14 @@ 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 { - label: string; - url: string; } export interface InputBoxComponent extends Component, InputBoxProperties { diff --git a/src/sql/workbench/api/common/extHostModelView.ts b/src/sql/workbench/api/common/extHostModelView.ts index 722fd22910..220820dce8 100644 --- a/src/sql/workbench/api/common/extHostModelView.ts +++ b/src/sql/workbench/api/common/extHostModelView.ts @@ -1112,6 +1112,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 bf246361b1..28d2ad07c4 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 e7598bea54..384ee572b1 100644 --- a/src/sql/workbench/browser/modelComponents/text.component.ts +++ b/src/sql/workbench/browser/modelComponents/text.component.ts @@ -11,16 +11,16 @@ 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); + } +}