mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Feature/selectable card component (#1703)
* added selectable card * creating new card type
This commit is contained in:
@@ -10,21 +10,16 @@ import {
|
|||||||
|
|
||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
|
|
||||||
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
import { ComponentWithIconBase } from 'sql/parts/modelComponents/componentWithIconBase';
|
||||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||||
import { attachButtonStyler } from 'sql/common/theme/styler';
|
import { attachButtonStyler } from 'sql/common/theme/styler';
|
||||||
import { Button } from 'sql/base/browser/ui/button/button';
|
import { Button } from 'sql/base/browser/ui/button/button';
|
||||||
|
|
||||||
import { SIDE_BAR_BACKGROUND, SIDE_BAR_TITLE_FOREGROUND } from 'vs/workbench/common/theme';
|
import { SIDE_BAR_BACKGROUND, SIDE_BAR_TITLE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
|
||||||
import URI from 'vs/base/common/uri';
|
|
||||||
import { IdGenerator } from 'vs/base/common/idGenerator';
|
|
||||||
import { createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom';
|
|
||||||
import { focusBorder, foreground } from 'vs/platform/theme/common/colorRegistry';
|
import { focusBorder, foreground } from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
|
|
||||||
type IUserFriendlyIcon = string | URI | { light: string | URI; dark: string | URI };
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'modelview-button',
|
selector: 'modelview-button',
|
||||||
@@ -32,12 +27,10 @@ type IUserFriendlyIcon = string | URI | { light: string | URI; dark: string | UR
|
|||||||
<div #input style="width: 100%"></div>
|
<div #input style="width: 100%"></div>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export default class ButtonComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
|
export default class ButtonComponent extends ComponentWithIconBase implements IComponent, OnDestroy, AfterViewInit {
|
||||||
@Input() descriptor: IComponentDescriptor;
|
@Input() descriptor: IComponentDescriptor;
|
||||||
@Input() modelStore: IModelStore;
|
@Input() modelStore: IModelStore;
|
||||||
private _button: Button;
|
private _button: Button;
|
||||||
private _iconClass: string;
|
|
||||||
private _iconPath: IUserFriendlyIcon;
|
|
||||||
|
|
||||||
@ViewChild('input', { read: ElementRef }) private _inputContainer: ElementRef;
|
@ViewChild('input', { read: ElementRef }) private _inputContainer: ElementRef;
|
||||||
constructor(
|
constructor(
|
||||||
@@ -71,9 +64,6 @@ export default class ButtonComponent extends ComponentBase implements IComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this._iconClass) {
|
|
||||||
removeCSSRulesContainingSelector(this._iconClass);
|
|
||||||
}
|
|
||||||
this.baseDestroy();
|
this.baseDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,14 +91,11 @@ export default class ButtonComponent extends ComponentBase implements IComponent
|
|||||||
this.updateIcon();
|
this.updateIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateIcon() {
|
protected updateIcon() {
|
||||||
if (this.iconPath && this.iconPath !== this._iconPath) {
|
if (this.iconPath) {
|
||||||
this._iconPath = this.iconPath;
|
|
||||||
if (!this._iconClass) {
|
if (!this._iconClass) {
|
||||||
const ids = new IdGenerator('button-component-icon-' + Math.round(Math.random() * 1000));
|
super.updateIcon();
|
||||||
this._iconClass = ids.nextId();
|
|
||||||
this._button.icon = this._iconClass + ' icon';
|
this._button.icon = this._iconClass + ' icon';
|
||||||
|
|
||||||
// Styling for icon button
|
// Styling for icon button
|
||||||
this._register(attachButtonStyler(this._button, this.themeService, {
|
this._register(attachButtonStyler(this._button, this.themeService, {
|
||||||
buttonBackground: Color.transparent.toString(),
|
buttonBackground: Color.transparent.toString(),
|
||||||
@@ -117,36 +104,6 @@ export default class ButtonComponent extends ComponentBase implements IComponent
|
|||||||
buttonForeground: foreground
|
buttonForeground: foreground
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeCSSRulesContainingSelector(this._iconClass);
|
|
||||||
const icon = this.getLightIconPath(this.iconPath);
|
|
||||||
const iconDark = this.getDarkIconPath(this.iconPath) || icon;
|
|
||||||
createCSSRule(`.icon.${this._iconClass}`, `background-image: url("${icon}")`);
|
|
||||||
createCSSRule(`.vs-dark .icon.${this._iconClass}, .hc-black .icon.${this._iconClass}`, `background-image: url("${iconDark}")`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getLightIconPath(iconPath: IUserFriendlyIcon): string {
|
|
||||||
if (iconPath && iconPath['light']) {
|
|
||||||
return this.getIconPath(iconPath['light']);
|
|
||||||
} else {
|
|
||||||
return this.getIconPath(<string | URI>iconPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getDarkIconPath(iconPath: IUserFriendlyIcon): string {
|
|
||||||
if (iconPath && iconPath['dark']) {
|
|
||||||
return this.getIconPath(iconPath['dark']);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getIconPath(iconPath: string | URI): string {
|
|
||||||
if (typeof iconPath === 'string') {
|
|
||||||
return URI.file(iconPath).toString();
|
|
||||||
} else {
|
|
||||||
let uri = URI.revive(iconPath);
|
|
||||||
return uri.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,13 +117,7 @@ export default class ButtonComponent extends ComponentBase implements IComponent
|
|||||||
this.setPropertyFromUI<sqlops.ButtonProperties, string>(this.setValueProperties, newValue);
|
this.setPropertyFromUI<sqlops.ButtonProperties, string>(this.setValueProperties, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get iconPath(): string | URI | { light: string | URI; dark: string | URI } {
|
|
||||||
return this.getPropertyOrDefault<sqlops.ButtonProperties, IUserFriendlyIcon>((props) => props.iconPath, undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
public set iconPath(newValue: string | URI | { light: string | URI; dark: string | URI }) {
|
|
||||||
this.setPropertyFromUI<sqlops.ButtonProperties, IUserFriendlyIcon>((properties, iconPath) => { properties.iconPath = iconPath; }, newValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private setValueProperties(properties: sqlops.ButtonProperties, label: string): void {
|
private setValueProperties(properties: sqlops.ButtonProperties, label: string): void {
|
||||||
properties.label = label;
|
properties.label = label;
|
||||||
|
|||||||
@@ -1,19 +1,32 @@
|
|||||||
<div *ngIf="label" class="model-card">
|
<div *ngIf="label" [class]="getClass()" (click)="onCardClick()" (mouseover)="onCardHoverChanged($event)" (mouseout)="onCardHoverChanged($event)">
|
||||||
<span *ngIf="hasStatus" class="card-status">
|
<span *ngIf="hasStatus" class="card-status">
|
||||||
<div class="status-content" [style.backgroundColor]="statusColor"></div>
|
<div class="status-content" [style.backgroundColor]="statusColor"></div>
|
||||||
</span>
|
</span>
|
||||||
<div class="card-content">
|
|
||||||
<h4 class="card-label">{{label}}</h4>
|
<ng-container *ngIf="isVerticalButton">
|
||||||
<p class="card-value">{{value}}</p>
|
<div class="card-vertical-button">
|
||||||
<span *ngIf="actions">
|
<div *ngIf="iconPath" class="iconContainer"><div [class]="iconClass" [style.width]="iconWidth" [style.height]="iconHeight"></div>
|
||||||
<table class="model-table">
|
<hr/>
|
||||||
<tr *ngFor="let action of actions">
|
<h4 class="card-label">{{label}}</h4>
|
||||||
<td class="table-row">{{action.label}}</td>
|
</div>
|
||||||
<td *ngIf="action.actionTitle" class="table-row">
|
</div>
|
||||||
<a class="pointer prominent" (click)="onDidActionClick(action)">{{action.actionTitle}}</a>
|
</ng-container>
|
||||||
</td>
|
|
||||||
</tr>
|
<ng-container *ngIf="isDetailsCard">
|
||||||
</table>
|
<div class="card-content">
|
||||||
</span>
|
<h4 class="card-label">{{label}}</h4>
|
||||||
</div>
|
<p class="card-value">{{value}}</p>
|
||||||
|
<span *ngIf="actions">
|
||||||
|
<table class="model-table">
|
||||||
|
<tr *ngFor="let action of actions">
|
||||||
|
<td class="table-row">{{action.label}}</td>
|
||||||
|
<td *ngIf="action.actionTitle" class="table-row">
|
||||||
|
<a class="pointer prominent" (click)="onDidActionClick(action)">{{action.actionTitle}}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -15,14 +15,14 @@ import * as colors from 'vs/platform/theme/common/colorRegistry';
|
|||||||
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
|
|
||||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||||
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
import { ComponentWithIconBase } from 'sql/parts/modelComponents/componentWithIconBase';
|
||||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||||
import { StatusIndicator, CardProperties, ActionDescriptor } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { StatusIndicator, CardProperties, ActionDescriptor } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: decodeURI(require.toUrl('sql/parts/modelComponents/card.component.html'))
|
templateUrl: decodeURI(require.toUrl('sql/parts/modelComponents/card.component.html'))
|
||||||
})
|
})
|
||||||
export default class CardComponent extends ComponentBase implements IComponent, OnDestroy {
|
export default class CardComponent extends ComponentWithIconBase implements IComponent, OnDestroy {
|
||||||
@Input() descriptor: IComponentDescriptor;
|
@Input() descriptor: IComponentDescriptor;
|
||||||
@Input() modelStore: IModelStore;
|
@Input() modelStore: IModelStore;
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ export default class CardComponent extends ComponentBase implements IComponent,
|
|||||||
|
|
||||||
constructor(@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
|
constructor(@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
|
||||||
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
|
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
|
||||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
|
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
|
||||||
) {
|
) {
|
||||||
super(changeRef);
|
super(changeRef);
|
||||||
}
|
}
|
||||||
@@ -46,6 +46,39 @@ export default class CardComponent extends ComponentBase implements IComponent,
|
|||||||
this.baseDestroy();
|
this.baseDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _defaultBorderColor = 'rgb(214, 214, 214)';
|
||||||
|
private _hasFocus: boolean;
|
||||||
|
|
||||||
|
public onCardClick() {
|
||||||
|
if (this.selectable) {
|
||||||
|
this.selected = !this.selected;
|
||||||
|
this._changeRef.detectChanges();
|
||||||
|
this._onEventEmitter.fire({
|
||||||
|
eventType: ComponentEventType.onDidClick,
|
||||||
|
args: this.selected
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBorderColor() {
|
||||||
|
if (this.selectable && this.selected || this._hasFocus) {
|
||||||
|
return 'Blue';
|
||||||
|
} else {
|
||||||
|
return this._defaultBorderColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getClass(): string {
|
||||||
|
return (this.selectable && this.selected || this._hasFocus) ? 'model-card selected' :
|
||||||
|
'model-card unselected';
|
||||||
|
}
|
||||||
|
|
||||||
|
public onCardHoverChanged(event: any) {
|
||||||
|
if (this.selectable) {
|
||||||
|
this._hasFocus = event.type === 'mouseover';
|
||||||
|
this._changeRef.detectChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
/// IComponent implementation
|
/// IComponent implementation
|
||||||
|
|
||||||
public layout(): void {
|
public layout(): void {
|
||||||
@@ -57,6 +90,19 @@ export default class CardComponent extends ComponentBase implements IComponent,
|
|||||||
this.layout();
|
this.layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setProperties(properties: { [key: string]: any; }): void {
|
||||||
|
super.setProperties(properties);
|
||||||
|
this.updateIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get iconClass(): string {
|
||||||
|
return this._iconClass + ' icon' + ' cardIcon';
|
||||||
|
}
|
||||||
|
|
||||||
|
private get selectable(): boolean {
|
||||||
|
return this.cardType === 'VerticalButton';
|
||||||
|
}
|
||||||
|
|
||||||
// CSS-bound properties
|
// CSS-bound properties
|
||||||
|
|
||||||
public get label(): string {
|
public get label(): string {
|
||||||
@@ -67,6 +113,27 @@ export default class CardComponent extends ComponentBase implements IComponent,
|
|||||||
return this.getPropertyOrDefault<CardProperties, string>((props) => props.value, '');
|
return this.getPropertyOrDefault<CardProperties, string>((props) => props.value, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get cardType(): string {
|
||||||
|
return this.getPropertyOrDefault<CardProperties, string>((props) => props.cardType, 'Details');
|
||||||
|
}
|
||||||
|
|
||||||
|
public get selected(): boolean {
|
||||||
|
return this.getPropertyOrDefault<sqlops.CardProperties, boolean>((props) => props.selected, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public set selected(newValue: boolean) {
|
||||||
|
this.setPropertyFromUI<sqlops.CardProperties, boolean>((props, value) => props.selected = value, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isDetailsCard(): boolean {
|
||||||
|
return !this.cardType || this.cardType === 'Details';
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isVerticalButton(): boolean {
|
||||||
|
return this.cardType === 'VerticalButton';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public get actions(): ActionDescriptor[] {
|
public get actions(): ActionDescriptor[] {
|
||||||
return this.getPropertyOrDefault<CardProperties, ActionDescriptor[]>((props) => props.actions, []);
|
return this.getPropertyOrDefault<CardProperties, ActionDescriptor[]>((props) => props.actions, []);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,26 @@
|
|||||||
margin: 15px;
|
margin: 15px;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-color: rgb(214, 214, 214);
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
box-shadow: rgba(120, 120, 120, 0.75) 0px 0px 6px;
|
box-shadow: rgba(120, 120, 120, 0.75) 0px 0px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.model-card.selected {
|
||||||
|
border-color: darkblue
|
||||||
|
}
|
||||||
|
|
||||||
|
.vs-dark .monaco-workbench .model-card.selected,
|
||||||
|
.hc-black .monaco-workbench .model-card.selected {
|
||||||
|
border-color: darkblue
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-card.unselected {
|
||||||
|
border-color: rgb(214, 214, 214);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.model-card .card-content {
|
.model-card .card-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -23,6 +37,16 @@
|
|||||||
min-width: 30px;
|
min-width: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.model-card .card-vertical-button {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
padding: 5px 5px 5px 5px;
|
||||||
|
min-height: 130px;
|
||||||
|
min-width: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
.model-card .card-label {
|
.model-card .card-label {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -33,6 +57,19 @@
|
|||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.model-card .iconContainer {
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0px 10px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.model-card .cardIcon {
|
||||||
|
display: inline-block;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
.model-card .card-status {
|
.model-card .card-status {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 7px;
|
top: 7px;
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboar
|
|||||||
import { Event, Emitter } from 'vs/base/common/event';
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component';
|
import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component';
|
||||||
|
import URI from 'vs/base/common/uri';
|
||||||
|
import { IdGenerator } from 'vs/base/common/idGenerator';
|
||||||
|
import { createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom';
|
||||||
|
|
||||||
|
|
||||||
|
export type IUserFriendlyIcon = string | URI | { light: string | URI; dark: string | URI };
|
||||||
|
|
||||||
export class ItemDescriptor<T> {
|
export class ItemDescriptor<T> {
|
||||||
constructor(public descriptor: IComponentDescriptor, public config: T) { }
|
constructor(public descriptor: IComponentDescriptor, public config: T) { }
|
||||||
|
|||||||
107
src/sql/parts/modelComponents/componentWithIconBase.ts
Normal file
107
src/sql/parts/modelComponents/componentWithIconBase.ts
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
||||||
|
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, OnInit, QueryList
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import { IComponent, IComponentDescriptor, IModelStore, IComponentEventArgs, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||||
|
import * as sqlops from 'sqlops';
|
||||||
|
import URI from 'vs/base/common/uri';
|
||||||
|
import { IdGenerator } from 'vs/base/common/idGenerator';
|
||||||
|
import { createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom';
|
||||||
|
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
||||||
|
|
||||||
|
|
||||||
|
export type IUserFriendlyIcon = string | URI | { light: string | URI; dark: string | URI };
|
||||||
|
|
||||||
|
export class ItemDescriptor<T> {
|
||||||
|
constructor(public descriptor: IComponentDescriptor, public config: T) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class ComponentWithIconBase extends ComponentBase {
|
||||||
|
|
||||||
|
protected _iconClass: string;
|
||||||
|
protected _iconPath: IUserFriendlyIcon;
|
||||||
|
constructor(
|
||||||
|
changeRef: ChangeDetectorRef) {
|
||||||
|
super(changeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IComponent implementation
|
||||||
|
|
||||||
|
public get iconClass(): string {
|
||||||
|
return this._iconClass + ' icon';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updateIcon() {
|
||||||
|
if (this.iconPath && this.iconPath !== this._iconPath) {
|
||||||
|
this._iconPath = this.iconPath;
|
||||||
|
if (!this._iconClass) {
|
||||||
|
const ids = new IdGenerator('model-view-component-icon-' + Math.round(Math.random() * 1000));
|
||||||
|
this._iconClass = ids.nextId();
|
||||||
|
}
|
||||||
|
|
||||||
|
removeCSSRulesContainingSelector(this._iconClass);
|
||||||
|
const icon = this.getLightIconPath(this.iconPath);
|
||||||
|
const iconDark = this.getDarkIconPath(this.iconPath) || icon;
|
||||||
|
createCSSRule(`.icon.${this._iconClass}`, `background-image: url("${icon}")`);
|
||||||
|
createCSSRule(`.vs-dark .icon.${this._iconClass}, .hc-black .icon.${this._iconClass}`, `background-image: url("${iconDark}")`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getLightIconPath(iconPath: IUserFriendlyIcon): string {
|
||||||
|
if (iconPath && iconPath['light']) {
|
||||||
|
return this.getIconPath(iconPath['light']);
|
||||||
|
} else {
|
||||||
|
return this.getIconPath(<string | URI>iconPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getDarkIconPath(iconPath: IUserFriendlyIcon): string {
|
||||||
|
if (iconPath && iconPath['dark']) {
|
||||||
|
return this.getIconPath(iconPath['dark']);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getIconPath(iconPath: string | URI): string {
|
||||||
|
if (typeof iconPath === 'string') {
|
||||||
|
return URI.file(iconPath).toString();
|
||||||
|
} else {
|
||||||
|
let uri = URI.revive(iconPath);
|
||||||
|
return uri.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getIconWidth(): string {
|
||||||
|
return this.convertSize(this.iconWidth, '40px');
|
||||||
|
}
|
||||||
|
|
||||||
|
public getIconHeight(): string {
|
||||||
|
return this.convertSize(this.iconHeight, '40px');
|
||||||
|
}
|
||||||
|
|
||||||
|
public get iconPath(): string | URI | { light: string | URI; dark: string | URI } {
|
||||||
|
return this.getPropertyOrDefault<sqlops.ComponentWithIcon, IUserFriendlyIcon>((props) => props.iconPath, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get iconHeight(): number | string {
|
||||||
|
return this.getPropertyOrDefault<sqlops.ComponentWithIcon, number | string>((props) => props.iconHeight, '40px');
|
||||||
|
}
|
||||||
|
|
||||||
|
public get iconWidth(): number | string {
|
||||||
|
return this.getPropertyOrDefault<sqlops.ComponentWithIcon, number | string>((props) => props.iconWidth, '40px');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (this._iconClass) {
|
||||||
|
removeCSSRulesContainingSelector(this._iconClass);
|
||||||
|
}
|
||||||
|
super.ngOnDestroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ export interface TitledFormItemLayout {
|
|||||||
horizontal: boolean;
|
horizontal: boolean;
|
||||||
componentWidth?: number | string;
|
componentWidth?: number | string;
|
||||||
componentHeight?: number | string;
|
componentHeight?: number | string;
|
||||||
titleFontSize?: number;
|
titleFontSize?: number | string;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
info?: string;
|
info?: string;
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,7 @@ class FormItem {
|
|||||||
<ng-container *ngIf="isHorizontal(item)">
|
<ng-container *ngIf="isHorizontal(item)">
|
||||||
<div class="form-cell" [style.font-size]="getItemTitleFontSize(item)">
|
<div class="form-cell" [style.font-size]="getItemTitleFontSize(item)">
|
||||||
{{getItemTitle(item)}}<span class="form-required" *ngIf="isItemRequired(item)">*</span>
|
{{getItemTitle(item)}}<span class="form-required" *ngIf="isItemRequired(item)">*</span>
|
||||||
<span class="icon info" *ngIf="itemHasInfo(item)" [title]="getItemInfo(item)"></span>
|
<span class="icon info form-info" *ngIf="itemHasInfo(item)" [title]="getItemInfo(item)"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-cell">
|
<div class="form-cell">
|
||||||
<div class="form-component-container">
|
<div class="form-component-container">
|
||||||
@@ -68,7 +68,7 @@ class FormItem {
|
|||||||
<div class="form-vertical-container" *ngIf="isVertical(item)" [style.height]="getRowHeight(item)">
|
<div class="form-vertical-container" *ngIf="isVertical(item)" [style.height]="getRowHeight(item)">
|
||||||
<div class="form-item-row" [style.font-size]="getItemTitleFontSize(item)">
|
<div class="form-item-row" [style.font-size]="getItemTitleFontSize(item)">
|
||||||
{{getItemTitle(item)}}<span class="form-required" *ngIf="isItemRequired(item)">*</span>
|
{{getItemTitle(item)}}<span class="form-required" *ngIf="isItemRequired(item)">*</span>
|
||||||
<span class="icon info" *ngIf="itemHasInfo(item)" [title]="getItemInfo(item)"></span>
|
<span class="icon info form-info" *ngIf="itemHasInfo(item)" [title]="getItemInfo(item)"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-item-row" [style.width]="getComponentWidth(item)" [style.height]="getRowHeight(item)">
|
<div class="form-item-row" [style.width]="getComponentWidth(item)" [style.height]="getRowHeight(item)">
|
||||||
<model-component-wrapper [descriptor]="item.descriptor" [modelStore]="modelStore" [style.width]="getComponentWidth(item)" [style.height]="getRowHeight(item)">
|
<model-component-wrapper [descriptor]="item.descriptor" [modelStore]="modelStore" [style.width]="getComponentWidth(item)" [style.height]="getRowHeight(item)">
|
||||||
|
|||||||
@@ -42,6 +42,11 @@
|
|||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-info {
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
.form-component-actions {
|
.form-component-actions {
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/sql/sqlops.proposed.d.ts
vendored
26
src/sql/sqlops.proposed.d.ts
vendored
@@ -239,7 +239,7 @@ declare module 'sqlops' {
|
|||||||
horizontal?: boolean;
|
horizontal?: boolean;
|
||||||
componentWidth?: number | string;
|
componentWidth?: number | string;
|
||||||
componentHeight?: number | string;
|
componentHeight?: number | string;
|
||||||
titleFontSize?: number;
|
titleFontSize?: number | string;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
info?: string;
|
info?: string;
|
||||||
}
|
}
|
||||||
@@ -300,15 +300,22 @@ declare module 'sqlops' {
|
|||||||
Error = 3
|
Error = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CardType {
|
||||||
|
VerticalButton = 'VerticalButton',
|
||||||
|
Details = 'Details'
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Properties representing the card component, can be used
|
* Properties representing the card component, can be used
|
||||||
* when using ModelBuilder to create the component
|
* when using ModelBuilder to create the component
|
||||||
*/
|
*/
|
||||||
export interface CardProperties {
|
export interface CardProperties extends ComponentWithIcon {
|
||||||
label: string;
|
label: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
actions?: ActionDescriptor[];
|
actions?: ActionDescriptor[];
|
||||||
status?: StatusIndicator;
|
status?: StatusIndicator;
|
||||||
|
selected?: boolean;
|
||||||
|
cardType: CardType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type InputBoxInputType = 'color' | 'date' | 'datetime-local' | 'email' | 'month' | 'number' | 'password' | 'range' | 'search' | 'text' | 'time' | 'url' | 'week';
|
export type InputBoxInputType = 'color' | 'date' | 'datetime-local' | 'email' | 'month' | 'number' | 'password' | 'range' | 'search' | 'text' | 'time' | 'url' | 'week';
|
||||||
@@ -318,6 +325,12 @@ declare module 'sqlops' {
|
|||||||
width?: number | string;
|
width?: number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ComponentWithIcon {
|
||||||
|
iconPath?: string | vscode.Uri | { light: string | vscode.Uri; dark: string | vscode.Uri };
|
||||||
|
iconHeight?: number | string;
|
||||||
|
iconWidth?: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface InputBoxProperties extends ComponentProperties {
|
export interface InputBoxProperties extends ComponentProperties {
|
||||||
value?: string;
|
value?: string;
|
||||||
ariaLabel?: string;
|
ariaLabel?: string;
|
||||||
@@ -393,20 +406,17 @@ declare module 'sqlops' {
|
|||||||
html?: string;
|
html?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ButtonProperties extends ComponentProperties {
|
export interface ButtonProperties extends ComponentProperties, ComponentWithIcon {
|
||||||
label?: string;
|
label?: string;
|
||||||
iconPath?: string | vscode.Uri | { light: string | vscode.Uri; dark: string | vscode.Uri };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingComponentProperties {
|
export interface LoadingComponentProperties {
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CardComponent extends Component {
|
export interface CardComponent extends Component, CardProperties {
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
actions?: ActionDescriptor[];
|
|
||||||
onDidActionClick: vscode.Event<ActionDescriptor>;
|
onDidActionClick: vscode.Event<ActionDescriptor>;
|
||||||
|
onCardSelectedChanged: vscode.Event<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TextComponent extends Component {
|
export interface TextComponent extends Component {
|
||||||
|
|||||||
@@ -208,6 +208,8 @@ export interface CardProperties {
|
|||||||
value?: string;
|
value?: string;
|
||||||
actions?: ActionDescriptor[];
|
actions?: ActionDescriptor[];
|
||||||
status?: StatusIndicator;
|
status?: StatusIndicator;
|
||||||
|
selected?: boolean;
|
||||||
|
cardType: CardType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ActionDescriptor {
|
export interface ActionDescriptor {
|
||||||
@@ -237,3 +239,8 @@ export enum DeclarativeDataType {
|
|||||||
category = 'category',
|
category = 'category',
|
||||||
boolean = 'boolean'
|
boolean = 'boolean'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CardType {
|
||||||
|
VerticalButton = 'VerticalButton',
|
||||||
|
Details = 'Details'
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ import * as vscode from 'vscode';
|
|||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
|
|
||||||
import { SqlMainContext, ExtHostModelViewShape, MainThreadModelViewShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
import { SqlMainContext, ExtHostModelViewShape, MainThreadModelViewShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
|
||||||
import { IItemConfig, ModelComponentTypes, IComponentShape, IComponentEventArgs, ComponentEventType } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { IItemConfig, ModelComponentTypes, IComponentShape, IComponentEventArgs, ComponentEventType, CardType } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
class ModelBuilderImpl implements sqlops.ModelBuilder {
|
class ModelBuilderImpl implements sqlops.ModelBuilder {
|
||||||
private nextComponentId: number;
|
private nextComponentId: number;
|
||||||
@@ -523,6 +523,7 @@ class CardWrapper extends ComponentWrapper implements sqlops.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 {
|
||||||
@@ -537,17 +538,53 @@ class CardWrapper extends ComponentWrapper implements sqlops.CardComponent {
|
|||||||
public set value(v: string) {
|
public set value(v: string) {
|
||||||
this.setProperty('value', v);
|
this.setProperty('value', v);
|
||||||
}
|
}
|
||||||
|
public get selected(): boolean {
|
||||||
|
return this.properties['selected'];
|
||||||
|
}
|
||||||
|
public set selected(v: boolean) {
|
||||||
|
this.setProperty('selected', v);
|
||||||
|
}
|
||||||
|
public get cardType(): sqlops.CardType {
|
||||||
|
return this.properties['cardType'];
|
||||||
|
}
|
||||||
|
public set cardType(v: sqlops.CardType) {
|
||||||
|
this.setProperty('cardType', v);
|
||||||
|
}
|
||||||
public get actions(): sqlops.ActionDescriptor[] {
|
public get actions(): sqlops.ActionDescriptor[] {
|
||||||
return this.properties['actions'];
|
return this.properties['actions'];
|
||||||
}
|
}
|
||||||
public set actions(a: sqlops.ActionDescriptor[]) {
|
public set actions(a: sqlops.ActionDescriptor[]) {
|
||||||
this.setProperty('actions', a);
|
this.setProperty('actions', a);
|
||||||
}
|
}
|
||||||
|
public get iconPath(): string | URI | { light: string | URI; dark: string | URI } {
|
||||||
|
return this.properties['iconPath'];
|
||||||
|
}
|
||||||
|
public set iconPath(v: string | URI | { light: string | URI; dark: string | URI }) {
|
||||||
|
this.setProperty('iconPath', v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get iconHeight(): number | string {
|
||||||
|
return this.properties['iconHeight'];
|
||||||
|
}
|
||||||
|
public set iconHeight(v: number | string) {
|
||||||
|
this.setProperty('iconHeight', v);
|
||||||
|
}
|
||||||
|
public get iconWidth(): number | string {
|
||||||
|
return this.properties['iconWidth'];
|
||||||
|
}
|
||||||
|
public set iconWidth(v: number | string) {
|
||||||
|
this.setProperty('iconWidth', v);
|
||||||
|
}
|
||||||
|
|
||||||
public get onDidActionClick(): vscode.Event<sqlops.ActionDescriptor> {
|
public get onDidActionClick(): vscode.Event<sqlops.ActionDescriptor> {
|
||||||
let emitter = this._emitterMap.get(ComponentEventType.onDidClick);
|
let emitter = this._emitterMap.get(ComponentEventType.onDidClick);
|
||||||
return emitter && emitter.event;
|
return emitter && emitter.event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get onCardSelectedChanged(): vscode.Event<any> {
|
||||||
|
let emitter = this._emitterMap.get(ComponentEventType.onDidClick);
|
||||||
|
return emitter && emitter.event;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InputBoxWrapper extends ComponentWrapper implements sqlops.InputBoxComponent {
|
class InputBoxWrapper extends ComponentWrapper implements sqlops.InputBoxComponent {
|
||||||
|
|||||||
@@ -391,7 +391,8 @@ export function createApiFactory(
|
|||||||
workspace,
|
workspace,
|
||||||
queryeditor: queryEditor,
|
queryeditor: queryEditor,
|
||||||
ui: ui,
|
ui: ui,
|
||||||
StatusIndicator: sqlExtHostTypes.StatusIndicator
|
StatusIndicator: sqlExtHostTypes.StatusIndicator,
|
||||||
|
CardType: sqlExtHostTypes.CardType
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user