Fix endpoint text overflowing and add title tooltip (#7390)

* Fix endpoint text overflowing and add title tooltip

* Remove unneeded string interning
This commit is contained in:
Charles Gagnon
2019-09-27 12:43:53 -07:00
committed by Karl Burtram
parent 30ae023d73
commit 7d27d2f4f4
10 changed files with 110 additions and 30 deletions

View File

@@ -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' };
}

View File

@@ -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<azdata.HyperlinkComponentProperties>({
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<azdata.TextComponentProperties>({
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<azdata.TextComponentProperties>({
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;

View File

@@ -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<azdata.TextComponentProperties>({ 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<azdata.HyperlinkComponentProperties>({ 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<azdata.HyperlinkComponentProperties>({
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<azdata.TextComponentProperties>({ value: endpointInfo.endpoint }).component();
const endpointCell =
view.modelBuilder.text()
.withProperties<azdata.TextComponentProperties>(
{
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();

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

@@ -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<ActionDescriptor>;
onCardSelectedChanged: vscode.Event<any>;
@@ -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 {

View File

@@ -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<ActionDescriptor>;
onCardSelectedChanged: vscode.Event<any>;
@@ -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<any>;
}
export interface HyperlinkComponent extends Component, HyperlinkComponentProperties {
label: string;
url: string;
}
export interface InputBoxComponent extends Component, InputBoxProperties {

View File

@@ -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<any> {
let emitter = this._emitterMap.get(ComponentEventType.onDidClick);
return emitter && emitter.event;

View File

@@ -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: `<a [href]="getUrl()" target="blank">{{getLabel()}}</a>`
template: `<a [href]="getUrl()" [title]="title" target="blank">{{getLabel()}}</a>`
})
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;

View File

@@ -101,3 +101,7 @@ export interface IModelStore {
*/
validate(component: IComponent): Thenable<boolean>;
}
export interface ITitledComponent {
title?: string;
}

View File

@@ -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: `
<p [style.width]="getWidth()" [innerHTML]="getValue()" [ngStyle]="this.CSSStyles" (click)="onClick()"></p>`
<p [style.width]="getWidth()" [innerHTML]="getValue()" [title]="title" [ngStyle]="this.CSSStyles" (click)="onClick()"></p>`
})
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;

View File

@@ -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<azdata.HyperlinkComponentProperties, string>((props) => props.title, '');
}
public set title(newTitle: string) {
this.setPropertyFromUI<azdata.HyperlinkComponentProperties, string>((properties, title) => { properties.title = title; }, newTitle);
}
}