mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
added dropdown and form layout to model view (#1269)
* added dropdown and form layout to model view
This commit is contained in:
97
src/sql/parts/modelComponents/button.component.ts
Normal file
97
src/sql/parts/modelComponents/button.component.ts
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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, QueryList, AfterViewInit
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import * as sqlops from 'sqlops';
|
||||||
|
import Event, { Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
|
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
||||||
|
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||||
|
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||||
|
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||||
|
import { attachButtonStyler } from 'sql/common/theme/styler';
|
||||||
|
import { Button } from 'sql/base/browser/ui/button/button';
|
||||||
|
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'button',
|
||||||
|
template: `
|
||||||
|
<div #input style="width: 100%"></div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export default class ButtonComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
|
||||||
|
@Input() descriptor: IComponentDescriptor;
|
||||||
|
@Input() modelStore: IModelStore;
|
||||||
|
private _button: Button;
|
||||||
|
|
||||||
|
@ViewChild('input', { read: ElementRef }) private _inputContainer: ElementRef;
|
||||||
|
constructor(
|
||||||
|
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
|
||||||
|
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
|
||||||
|
super(changeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.baseInit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
if (this._inputContainer) {
|
||||||
|
|
||||||
|
|
||||||
|
this._button = new Button(this._inputContainer.nativeElement);
|
||||||
|
|
||||||
|
this._register(this._button);
|
||||||
|
this._register(attachButtonStyler(this._button, this._commonService.themeService, {
|
||||||
|
buttonBackground: SIDE_BAR_BACKGROUND, buttonHoverBackground: SIDE_BAR_BACKGROUND
|
||||||
|
}));
|
||||||
|
this._register(this._button.onDidClick(e => {
|
||||||
|
this._onEventEmitter.fire({
|
||||||
|
eventType: ComponentEventType.onDidClick,
|
||||||
|
args: e
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.baseDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IComponent implementation
|
||||||
|
|
||||||
|
public layout(): void {
|
||||||
|
this._changeRef.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public setLayout(layout: any): void {
|
||||||
|
// TODO allow configuring the look and feel
|
||||||
|
this.layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public setProperties(properties: { [key: string]: any; }): void {
|
||||||
|
super.setProperties(properties);
|
||||||
|
this._button.label = this.label;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSS-bound properties
|
||||||
|
|
||||||
|
private get label(): string {
|
||||||
|
return this.getPropertyOrDefault<sqlops.ButtonProperties, string>((props) => props.label, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
private set label(newValue: string) {
|
||||||
|
this.setPropertyFromUI<sqlops.ButtonProperties, string>(this.setValueProperties, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setValueProperties(properties: sqlops.ButtonProperties, label: string): void {
|
||||||
|
properties.label = label;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -75,7 +75,7 @@ export abstract class ComponentBase extends Disposable implements IComponent, On
|
|||||||
return types.isUndefinedOrNull(property) ? defaultVal : property;
|
return types.isUndefinedOrNull(property) ? defaultVal : property;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected setProperty<TPropertyBag, TValue>(propertySetter: (TPropertyBag, TValue) => void, value: TValue) {
|
protected setPropertyFromUI<TPropertyBag, TValue>(propertySetter: (TPropertyBag, TValue) => void, value: TValue) {
|
||||||
propertySetter(this.getProperties<TPropertyBag>(), value);
|
propertySetter(this.getProperties<TPropertyBag>(), value);
|
||||||
this._onEventEmitter.fire({
|
this._onEventEmitter.fire({
|
||||||
eventType: ComponentEventType.PropertiesChanged,
|
eventType: ComponentEventType.PropertiesChanged,
|
||||||
@@ -86,6 +86,12 @@ export abstract class ComponentBase extends Disposable implements IComponent, On
|
|||||||
public get onEvent(): Event<IComponentEventArgs> {
|
public get onEvent(): Event<IComponentEventArgs> {
|
||||||
return this._onEventEmitter.event;
|
return this._onEventEmitter.event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get title(): string {
|
||||||
|
let properties = this.getProperties();
|
||||||
|
let title = properties['title'];
|
||||||
|
return title ? <string>title : '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class ContainerBase<T> extends ComponentBase {
|
export abstract class ContainerBase<T> extends ComponentBase {
|
||||||
|
|||||||
@@ -4,16 +4,28 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import FlexContainer from './flexContainer.component';
|
import FlexContainer from './flexContainer.component';
|
||||||
|
import FormContainer from './formContainer.component';
|
||||||
import CardComponent from './card.component';
|
import CardComponent from './card.component';
|
||||||
import InputBoxComponent from './inputbox.component';
|
import InputBoxComponent from './inputbox.component';
|
||||||
|
import DropDownComponent from './dropdown.component';
|
||||||
|
import ButtonComponent from './button.component';
|
||||||
import { registerComponentType } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
import { registerComponentType } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
||||||
import { ModelComponentTypes } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { ModelComponentTypes } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
export const FLEX_CONTAINER = 'flex-container';
|
export const FLEX_CONTAINER = 'flex-container';
|
||||||
registerComponentType(FLEX_CONTAINER, ModelComponentTypes.FlexContainer, FlexContainer);
|
registerComponentType(FLEX_CONTAINER, ModelComponentTypes.FlexContainer, FlexContainer);
|
||||||
|
|
||||||
|
export const FORM_CONTAINER = 'form-container';
|
||||||
|
registerComponentType(FORM_CONTAINER, ModelComponentTypes.Form, FormContainer);
|
||||||
|
|
||||||
export const CARD_COMPONENT = 'card-component';
|
export const CARD_COMPONENT = 'card-component';
|
||||||
registerComponentType(CARD_COMPONENT, ModelComponentTypes.Card, CardComponent);
|
registerComponentType(CARD_COMPONENT, ModelComponentTypes.Card, CardComponent);
|
||||||
|
|
||||||
export const INPUTBOX_COMPONENT = 'inputbox-component';
|
export const INPUTBOX_COMPONENT = 'inputbox-component';
|
||||||
registerComponentType(INPUTBOX_COMPONENT, ModelComponentTypes.InputBox, InputBoxComponent);
|
registerComponentType(INPUTBOX_COMPONENT, ModelComponentTypes.InputBox, InputBoxComponent);
|
||||||
|
|
||||||
|
export const DROPDOWN_COMPONENT = 'dropdown-component';
|
||||||
|
registerComponentType(DROPDOWN_COMPONENT, ModelComponentTypes.DropDown, DropDownComponent);
|
||||||
|
|
||||||
|
export const BUTTON_COMPONENT = 'button-component';
|
||||||
|
registerComponentType(BUTTON_COMPONENT, ModelComponentTypes.Button, ButtonComponent);
|
||||||
|
|||||||
117
src/sql/parts/modelComponents/dropdown.component.ts
Normal file
117
src/sql/parts/modelComponents/dropdown.component.ts
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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, QueryList, AfterViewInit
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import * as sqlops from 'sqlops';
|
||||||
|
import Event, { Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
|
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
||||||
|
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||||
|
import { Dropdown, IDropdownOptions } from 'sql/base/browser/ui/editableDropdown/dropdown';
|
||||||
|
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||||
|
import { attachListStyler } from 'vs/platform/theme/common/styler';
|
||||||
|
import { attachEditableDropdownStyler } from 'sql/common/theme/styler';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'inputBox',
|
||||||
|
template: `
|
||||||
|
<div #input style="width: 100%"></div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export default class DropDownComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
|
||||||
|
@Input() descriptor: IComponentDescriptor;
|
||||||
|
@Input() modelStore: IModelStore;
|
||||||
|
private _dropdown: Dropdown;
|
||||||
|
|
||||||
|
@ViewChild('input', { read: ElementRef }) private _inputContainer: ElementRef;
|
||||||
|
constructor(
|
||||||
|
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
|
||||||
|
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
|
||||||
|
super(changeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.baseInit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
if (this._inputContainer) {
|
||||||
|
let dropdownOptions: IDropdownOptions = {
|
||||||
|
values: [],
|
||||||
|
strictSelection: false,
|
||||||
|
placeholder: '',
|
||||||
|
maxHeight: 125,
|
||||||
|
ariaLabel: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
this._dropdown = new Dropdown(this._inputContainer.nativeElement, this._commonService.contextViewService, this._commonService.themeService,
|
||||||
|
dropdownOptions);
|
||||||
|
|
||||||
|
this._register(this._dropdown);
|
||||||
|
this._register(attachEditableDropdownStyler(this._dropdown, this._commonService.themeService));
|
||||||
|
this._register(this._dropdown.onValueChange(e => {
|
||||||
|
this.value = this._dropdown.value;
|
||||||
|
this._onEventEmitter.fire({
|
||||||
|
eventType: ComponentEventType.onDidChange,
|
||||||
|
args: e
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.baseDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IComponent implementation
|
||||||
|
|
||||||
|
public layout(): void {
|
||||||
|
this._changeRef.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public setLayout(layout: any): void {
|
||||||
|
// TODO allow configuring the look and feel
|
||||||
|
this.layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public setProperties(properties: { [key: string]: any; }): void {
|
||||||
|
super.setProperties(properties);
|
||||||
|
this._dropdown.values = this.values ? this.values : [];
|
||||||
|
if (this.value) {
|
||||||
|
this._dropdown.value = this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSS-bound properties
|
||||||
|
|
||||||
|
private get value(): string {
|
||||||
|
return this.getPropertyOrDefault<sqlops.DropDownProperties, string>((props) => props.value, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
private set value(newValue: string) {
|
||||||
|
this.setPropertyFromUI<sqlops.DropDownProperties, string>(this.setValueProperties, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private get values(): string[] {
|
||||||
|
return this.getPropertyOrDefault<sqlops.DropDownProperties, string[]>((props) => props.values, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
private set values(newValue: string[]) {
|
||||||
|
this.setPropertyFromUI<sqlops.DropDownProperties, string[]>(this.setValuesProperties, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setValueProperties(properties: sqlops.DropDownProperties, value: string): void {
|
||||||
|
properties.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private setValuesProperties(properties: sqlops.DropDownProperties, values: string[]): void {
|
||||||
|
properties.values = values;
|
||||||
|
}
|
||||||
|
}
|
||||||
128
src/sql/parts/modelComponents/formContainer.component.ts
Normal file
128
src/sql/parts/modelComponents/formContainer.component.ts
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
import 'vs/css!./formLayout';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
||||||
|
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList, AfterViewInit
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||||
|
import { FormLayout, FormItemLayout } from 'sqlops';
|
||||||
|
|
||||||
|
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||||
|
import { ContainerBase } from 'sql/parts/modelComponents/componentBase';
|
||||||
|
import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component';
|
||||||
|
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||||
|
|
||||||
|
export interface TitledFormItemLayout {
|
||||||
|
title: string;
|
||||||
|
actions?: string[];
|
||||||
|
isFormComponent: Boolean;
|
||||||
|
}
|
||||||
|
class FormItem {
|
||||||
|
constructor(public descriptor: IComponentDescriptor, public config: TitledFormItemLayout) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
template: `
|
||||||
|
<div #container *ngIf="items" class="form-table"
|
||||||
|
[style.alignItems]="alignItems" [style.alignContent]="alignContent">
|
||||||
|
<div *ngFor="let item of items" class="form-row">
|
||||||
|
<ng-container *ngIf="isFormComponent(item)">
|
||||||
|
<div class="form-cell">{{getItemTitle(item)}}</div>
|
||||||
|
<div class="form-cell">
|
||||||
|
<model-component-wrapper [descriptor]="item.descriptor" [modelStore]="modelStore">
|
||||||
|
</model-component-wrapper>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="itemHasActions(item)" class="form-cell">
|
||||||
|
<div *ngFor="let actionItem of getActionComponents(item)" >
|
||||||
|
<model-component-wrapper [descriptor]="actionItem.descriptor" [modelStore]="modelStore">
|
||||||
|
</model-component-wrapper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export default class FormContainer extends ContainerBase<FormItemLayout> implements IComponent, OnDestroy, AfterViewInit {
|
||||||
|
@Input() descriptor: IComponentDescriptor;
|
||||||
|
@Input() modelStore: IModelStore;
|
||||||
|
|
||||||
|
private _alignItems: string;
|
||||||
|
private _alignContent: string;
|
||||||
|
|
||||||
|
@ViewChildren(ModelComponentWrapper) private _componentWrappers: QueryList<ModelComponentWrapper>;
|
||||||
|
@ViewChild('container', { read: ElementRef }) private _container: ElementRef;
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
@Inject(forwardRef(() => CommonServiceInterface)) private _commonService: CommonServiceInterface,
|
||||||
|
@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
|
||||||
|
super(changeRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.baseInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.baseDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IComponent implementation
|
||||||
|
|
||||||
|
public layout(): void {
|
||||||
|
if (this._componentWrappers) {
|
||||||
|
this._componentWrappers.forEach(wrapper => {
|
||||||
|
wrapper.layout();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get alignItems(): string {
|
||||||
|
return this._alignItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get alignContent(): string {
|
||||||
|
return this._alignContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getItemTitle(item: FormItem): string {
|
||||||
|
let itemConfig = item.config;
|
||||||
|
return itemConfig ? itemConfig.title : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
private getActionComponents(item: FormItem): FormItem[]{
|
||||||
|
let items = this.items;
|
||||||
|
let itemConfig = item.config;
|
||||||
|
if (itemConfig && itemConfig.actions) {
|
||||||
|
let resultItems = itemConfig.actions.map(x => {
|
||||||
|
let actionComponent = items.find(i => i.descriptor.id === x);
|
||||||
|
return <FormItem>actionComponent;
|
||||||
|
});
|
||||||
|
|
||||||
|
return resultItems.filter(r => r && r.descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private isFormComponent(item: FormItem): Boolean {
|
||||||
|
return item && item.config && item.config.isFormComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private itemHasActions(item: FormItem): Boolean {
|
||||||
|
let itemConfig = item.config;
|
||||||
|
return itemConfig && itemConfig.actions !== undefined && itemConfig.actions.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setLayout(layout: any): void {
|
||||||
|
this.layout();
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/sql/parts/modelComponents/formLayout.css
Normal file
20
src/sql/parts/modelComponents/formLayout.css
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
.form-table {
|
||||||
|
width:400px;
|
||||||
|
display:table;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
display: table-row;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-cell {
|
||||||
|
padding: 5px;
|
||||||
|
display: table-cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-action {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
import {
|
||||||
|
Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFactoryResolver,
|
||||||
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList, AfterViewInit
|
ViewChild, ViewChildren, ElementRef, Injector, OnDestroy, QueryList, AfterViewInit
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ export default class InputBoxComponent extends ComponentBase implements ICompone
|
|||||||
}
|
}
|
||||||
|
|
||||||
public set value(newValue: string) {
|
public set value(newValue: string) {
|
||||||
this.setProperty<sqlops.InputBoxProperties, string>(this.setInputBoxProperties, newValue);
|
this.setPropertyFromUI<sqlops.InputBoxProperties, string>(this.setInputBoxProperties, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setInputBoxProperties(properties: sqlops.InputBoxProperties, value: string): void {
|
private setInputBoxProperties(properties: sqlops.InputBoxProperties, value: string): void {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export interface IComponent {
|
|||||||
addToContainer?: (componentDescriptor: IComponentDescriptor, config: any) => void;
|
addToContainer?: (componentDescriptor: IComponentDescriptor, config: any) => void;
|
||||||
setLayout?: (layout: any) => void;
|
setLayout?: (layout: any) => void;
|
||||||
setProperties?: (properties: { [key: string]: any; }) => void;
|
setProperties?: (properties: { [key: string]: any; }) => void;
|
||||||
|
title?: string;
|
||||||
onEvent?: Event<IComponentEventArgs>;
|
onEvent?: Event<IComponentEventArgs>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,11 +54,13 @@ export interface IComponentDescriptor {
|
|||||||
export interface IComponentEventArgs {
|
export interface IComponentEventArgs {
|
||||||
eventType: ComponentEventType;
|
eventType: ComponentEventType;
|
||||||
args: any;
|
args: any;
|
||||||
|
componentId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ComponentEventType {
|
export enum ComponentEventType {
|
||||||
PropertiesChanged,
|
PropertiesChanged,
|
||||||
onDidChange
|
onDidChange,
|
||||||
|
onDidClick
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IModelStore {
|
export interface IModelStore {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
|||||||
import nls = require('vs/nls');
|
import nls = require('vs/nls');
|
||||||
|
|
||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
import { IModelStore, IComponentDescriptor, IComponent } from './interfaces';
|
import { IModelStore, IComponentDescriptor, IComponent, IComponentEventArgs } from './interfaces';
|
||||||
import { IItemConfig, ModelComponentTypes, IComponentShape } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { IItemConfig, ModelComponentTypes, IComponentShape } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
import { IModelView } from 'sql/services/model/modelViewService';
|
import { IModelView } from 'sql/services/model/modelViewService';
|
||||||
import { Extensions, IComponentRegistry } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
import { Extensions, IComponentRegistry } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
||||||
@@ -101,13 +101,14 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
|||||||
this.queueAction(componentId, (component) => {
|
this.queueAction(componentId, (component) => {
|
||||||
if (component.onEvent) {
|
if (component.onEvent) {
|
||||||
this._register(component.onEvent(e => {
|
this._register(component.onEvent(e => {
|
||||||
|
e.componentId = componentId;
|
||||||
this._onEventEmitter.fire(e);
|
this._onEventEmitter.fire(e);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public get onEvent(): Event<any> {
|
public get onEvent(): Event<IComponentEventArgs> {
|
||||||
return this._onEventEmitter.event;
|
return this._onEventEmitter.event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
45
src/sql/sqlops.proposed.d.ts
vendored
45
src/sql/sqlops.proposed.d.ts
vendored
@@ -20,8 +20,11 @@ declare module 'sqlops' {
|
|||||||
flexContainer(): FlexBuilder;
|
flexContainer(): FlexBuilder;
|
||||||
card(): ComponentBuilder<CardComponent>;
|
card(): ComponentBuilder<CardComponent>;
|
||||||
inputBox(): ComponentBuilder<InputBoxComponent>;
|
inputBox(): ComponentBuilder<InputBoxComponent>;
|
||||||
|
button(): ComponentBuilder<ButtonComponent>;
|
||||||
|
dropDown(): ComponentBuilder<DropDownComponent>;
|
||||||
dashboardWidget(widgetId: string): ComponentBuilder<WidgetComponent>;
|
dashboardWidget(widgetId: string): ComponentBuilder<WidgetComponent>;
|
||||||
dashboardWebview(webviewId: string): ComponentBuilder<WebviewComponent>;
|
dashboardWebview(webviewId: string): ComponentBuilder<WebviewComponent>;
|
||||||
|
formContainer(): FormBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ComponentBuilder<T extends Component> {
|
export interface ComponentBuilder<T extends Component> {
|
||||||
@@ -37,6 +40,10 @@ declare module 'sqlops' {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FormBuilder extends ContainerBuilder<FormContainer, FormLayout, FormItemLayout> {
|
||||||
|
withFormItems(components: FormComponent[], itemLayout?: FormItemLayout): ContainerBuilder<FormContainer, FormLayout, FormItemLayout>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Component {
|
export interface Component {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
|
|
||||||
@@ -50,6 +57,12 @@ declare module 'sqlops' {
|
|||||||
updateProperties(properties: { [key: string]: any }): Thenable<boolean>;
|
updateProperties(properties: { [key: string]: any }): Thenable<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FormComponent {
|
||||||
|
component: Component;
|
||||||
|
title: string;
|
||||||
|
actions?: Component[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component that contains other components
|
* A component that contains other components
|
||||||
*/
|
*/
|
||||||
@@ -130,9 +143,21 @@ declare module 'sqlops' {
|
|||||||
flex?: string;
|
flex?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FormItemLayout {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FormLayout {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export interface FlexContainer extends Container<FlexLayout, FlexItemLayout> {
|
export interface FlexContainer extends Container<FlexLayout, FlexItemLayout> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FormContainer extends Container<FormLayout, FormItemLayout> {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes an action to be shown in the UI, with a user-readable label
|
* Describes an action to be shown in the UI, with a user-readable label
|
||||||
* and a callback to execute the action
|
* and a callback to execute the action
|
||||||
@@ -163,6 +188,15 @@ declare module 'sqlops' {
|
|||||||
value?: string;
|
value?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DropDownProperties {
|
||||||
|
value?: string;
|
||||||
|
values?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ButtonProperties {
|
||||||
|
label?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CardComponent extends Component {
|
export interface CardComponent extends Component {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
@@ -174,6 +208,17 @@ declare module 'sqlops' {
|
|||||||
onTextChanged: vscode.Event<any>;
|
onTextChanged: vscode.Event<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DropDownComponent extends Component {
|
||||||
|
value: string;
|
||||||
|
values: string[];
|
||||||
|
onValueChanged: vscode.Event<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ButtonComponent extends Component {
|
||||||
|
label: string;
|
||||||
|
onDidClick: vscode.Event<any>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface WidgetComponent extends Component {
|
export interface WidgetComponent extends Component {
|
||||||
widgetId: string;
|
widgetId: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,8 +68,11 @@ export enum ModelComponentTypes {
|
|||||||
FlexContainer,
|
FlexContainer,
|
||||||
Card,
|
Card,
|
||||||
InputBox,
|
InputBox,
|
||||||
|
DropDown,
|
||||||
|
Button,
|
||||||
DashboardWidget,
|
DashboardWidget,
|
||||||
DashboardWebview
|
DashboardWebview,
|
||||||
|
Form
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IComponentShape {
|
export interface IComponentShape {
|
||||||
@@ -87,7 +90,8 @@ export interface IItemConfig {
|
|||||||
|
|
||||||
export enum ComponentEventType {
|
export enum ComponentEventType {
|
||||||
PropertiesChanged,
|
PropertiesChanged,
|
||||||
onDidChange
|
onDidChange,
|
||||||
|
onDidClick
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IComponentEventArgs {
|
export interface IComponentEventArgs {
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ class ModelBuilderImpl implements sqlops.ModelBuilder {
|
|||||||
return new ContainerBuilderImpl<sqlops.FlexContainer, sqlops.FlexLayout, sqlops.FlexItemLayout>(this._proxy, this._handle, ModelComponentTypes.FlexContainer, id);
|
return new ContainerBuilderImpl<sqlops.FlexContainer, sqlops.FlexLayout, sqlops.FlexItemLayout>(this._proxy, this._handle, ModelComponentTypes.FlexContainer, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
formContainer(): sqlops.FormBuilder {
|
||||||
|
let id = this.getNextComponentId();
|
||||||
|
return new FormContainerBuilder(this._proxy, this._handle, ModelComponentTypes.Form, id);
|
||||||
|
}
|
||||||
|
|
||||||
card(): sqlops.ComponentBuilder<sqlops.CardComponent> {
|
card(): sqlops.ComponentBuilder<sqlops.CardComponent> {
|
||||||
let id = this.getNextComponentId();
|
let id = this.getNextComponentId();
|
||||||
return this.withEventHandler(new CardWrapper(this._proxy, this._handle, id), id);
|
return this.withEventHandler(new CardWrapper(this._proxy, this._handle, id), id);
|
||||||
@@ -43,6 +48,16 @@ class ModelBuilderImpl implements sqlops.ModelBuilder {
|
|||||||
return this.withEventHandler(new InputBoxWrapper(this._proxy, this._handle, id), id);
|
return this.withEventHandler(new InputBoxWrapper(this._proxy, this._handle, id), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button(): sqlops.ComponentBuilder<sqlops.ButtonComponent> {
|
||||||
|
let id = this.getNextComponentId();
|
||||||
|
return this.withEventHandler(new ButtonWrapper(this._proxy, this._handle, id), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
dropDown(): sqlops.ComponentBuilder<sqlops.DropDownComponent> {
|
||||||
|
let id = this.getNextComponentId();
|
||||||
|
return this.withEventHandler(new DropDownWrapper(this._proxy, this._handle, id), id);
|
||||||
|
}
|
||||||
|
|
||||||
dashboardWidget(widgetId: string): sqlops.ComponentBuilder<sqlops.WidgetComponent> {
|
dashboardWidget(widgetId: string): sqlops.ComponentBuilder<sqlops.WidgetComponent> {
|
||||||
let id = this.getNextComponentId();
|
let id = this.getNextComponentId();
|
||||||
return this.withEventHandler<sqlops.WidgetComponent>(new ComponentWrapper(this._proxy, this._handle, ModelComponentTypes.DashboardWidget, id), id);
|
return this.withEventHandler<sqlops.WidgetComponent>(new ComponentWrapper(this._proxy, this._handle, ModelComponentTypes.DashboardWidget, id), id);
|
||||||
@@ -122,6 +137,37 @@ class ContainerBuilderImpl<T extends sqlops.Component, TLayout, TItemLayout> ext
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FormContainerBuilder extends ContainerBuilderImpl<sqlops.FormContainer, sqlops.FormLayout, sqlops.FormItemLayout> {
|
||||||
|
|
||||||
|
withFormItems(components: sqlops.FormComponent[], itemLayout?: sqlops.FormItemLayout): sqlops.ContainerBuilder<sqlops.FormContainer, sqlops.FormLayout, sqlops.FormItemLayout> {
|
||||||
|
|
||||||
|
this._component.itemConfigs = components.map(item => {
|
||||||
|
let componentWrapper = item.component as ComponentWrapper;
|
||||||
|
let actions: string[] = undefined;
|
||||||
|
if (item.actions) {
|
||||||
|
actions = item.actions.map(action => {
|
||||||
|
let actionComponentWrapper = action as ComponentWrapper;
|
||||||
|
return actionComponentWrapper.id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return new InternalItemConfig(componentWrapper, Object.assign({}, itemLayout, {
|
||||||
|
title: item.title,
|
||||||
|
actions: actions,
|
||||||
|
isFormComponent: true
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
components.forEach(formItem => {
|
||||||
|
if (formItem.actions) {
|
||||||
|
formItem.actions.forEach(component => {
|
||||||
|
let componentWrapper = component as ComponentWrapper;
|
||||||
|
this._component.itemConfigs.push(new InternalItemConfig(componentWrapper, itemLayout));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class InternalItemConfig {
|
class InternalItemConfig {
|
||||||
constructor(private _component: ComponentWrapper, public config: any) { }
|
constructor(private _component: ComponentWrapper, public config: any) { }
|
||||||
@@ -146,6 +192,7 @@ class ComponentWrapper implements sqlops.Component {
|
|||||||
|
|
||||||
private _onErrorEmitter = new Emitter<Error>();
|
private _onErrorEmitter = new Emitter<Error>();
|
||||||
public readonly onError: vscode.Event<Error> = this._onErrorEmitter.event;
|
public readonly onError: vscode.Event<Error> = this._onErrorEmitter.event;
|
||||||
|
protected _emitterMap = new Map<ComponentEventType, Emitter<any>>();
|
||||||
|
|
||||||
constructor(protected readonly _proxy: MainThreadModelViewShape,
|
constructor(protected readonly _proxy: MainThreadModelViewShape,
|
||||||
protected readonly _handle: number,
|
protected readonly _handle: number,
|
||||||
@@ -218,6 +265,11 @@ class ComponentWrapper implements sqlops.Component {
|
|||||||
public onEvent(eventArgs: IComponentEventArgs) {
|
public onEvent(eventArgs: IComponentEventArgs) {
|
||||||
if (eventArgs && eventArgs.eventType === ComponentEventType.PropertiesChanged) {
|
if (eventArgs && eventArgs.eventType === ComponentEventType.PropertiesChanged) {
|
||||||
this.properties = eventArgs.args;
|
this.properties = eventArgs.args;
|
||||||
|
} else if (eventArgs) {
|
||||||
|
let emitter = this._emitterMap.get(eventArgs.eventType);
|
||||||
|
if (emitter) {
|
||||||
|
emitter.fire();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,9 +330,6 @@ class InputBoxWrapper extends ComponentWrapper implements sqlops.InputBoxCompone
|
|||||||
this._emitterMap.set(ComponentEventType.onDidChange, new Emitter<any>());
|
this._emitterMap.set(ComponentEventType.onDidChange, new Emitter<any>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onTextChangedEmitter = new Emitter<any>();
|
|
||||||
private _emitterMap = new Map<ComponentEventType, Emitter<any>>();
|
|
||||||
|
|
||||||
public get value(): string {
|
public get value(): string {
|
||||||
return this.properties['value'];
|
return this.properties['value'];
|
||||||
}
|
}
|
||||||
@@ -292,15 +341,54 @@ class InputBoxWrapper extends ComponentWrapper implements sqlops.InputBoxCompone
|
|||||||
let emitter = this._emitterMap.get(ComponentEventType.onDidChange);
|
let emitter = this._emitterMap.get(ComponentEventType.onDidChange);
|
||||||
return emitter && emitter.event;
|
return emitter && emitter.event;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public onEvent(eventArgs: IComponentEventArgs) {
|
class DropDownWrapper extends ComponentWrapper implements sqlops.DropDownComponent {
|
||||||
super.onEvent(eventArgs);
|
|
||||||
if (eventArgs) {
|
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
|
||||||
let emitter = this._emitterMap.get(eventArgs.eventType);
|
super(proxy, handle, ModelComponentTypes.DropDown, id);
|
||||||
if (emitter) {
|
this.properties = {};
|
||||||
emitter.fire();
|
this._emitterMap.set(ComponentEventType.onDidChange, new Emitter<any>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public get value(): string {
|
||||||
|
return this.properties['value'];
|
||||||
|
}
|
||||||
|
public set value(v: string) {
|
||||||
|
this.setProperty('value', v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get values(): string[] {
|
||||||
|
return this.properties['values'];
|
||||||
|
}
|
||||||
|
public set values(v: string[]) {
|
||||||
|
this.setProperty('values', v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get onValueChanged(): vscode.Event<any> {
|
||||||
|
let emitter = this._emitterMap.get(ComponentEventType.onDidChange);
|
||||||
|
return emitter && emitter.event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ButtonWrapper extends ComponentWrapper implements sqlops.ButtonComponent {
|
||||||
|
|
||||||
|
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
|
||||||
|
super(proxy, handle, ModelComponentTypes.Button, id);
|
||||||
|
this.properties = {};
|
||||||
|
this._emitterMap.set(ComponentEventType.onDidClick, new Emitter<any>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public get label(): string {
|
||||||
|
return this.properties['label'];
|
||||||
|
}
|
||||||
|
public set label(v: string) {
|
||||||
|
this.setProperty('label', v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get onDidClick(): vscode.Event<any> {
|
||||||
|
let emitter = this._emitterMap.get(ComponentEventType.onDidClick);
|
||||||
|
return emitter && emitter.event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,9 @@ export class MainThreadModelView extends Disposable implements MainThreadModelVi
|
|||||||
let properties: { [key: string]: any; } = { eventName: this.onEvent };
|
let properties: { [key: string]: any; } = { eventName: this.onEvent };
|
||||||
return this.execModelViewAction(handle, (modelView) => {
|
return this.execModelViewAction(handle, (modelView) => {
|
||||||
this._register(modelView.onEvent(e => {
|
this._register(modelView.onEvent(e => {
|
||||||
|
if (e.componentId && e.componentId === componentId) {
|
||||||
this.onEvent(handle, componentId, e);
|
this.onEvent(handle, componentId, e);
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user