mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Feature/input box component (#1190)
* Adding new view component for input box
This commit is contained in:
@@ -10,25 +10,29 @@ import { Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFacto
|
|||||||
|
|
||||||
import * as types from 'vs/base/common/types';
|
import * as types from 'vs/base/common/types';
|
||||||
|
|
||||||
import { IComponent, IComponentDescriptor, IModelStore } from 'sql/parts/modelComponents/interfaces';
|
import { IComponent, IComponentDescriptor, IModelStore, IComponentEventArgs, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||||
import { FlexLayout, FlexItemLayout } from 'sqlops';
|
import { FlexLayout, FlexItemLayout } from 'sqlops';
|
||||||
import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost.directive';
|
import { ComponentHostDirective } from 'sql/parts/dashboard/common/componentHost.directive';
|
||||||
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
|
||||||
|
import Event, { Emitter } from 'vs/base/common/event';
|
||||||
|
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
export class ItemDescriptor<T> {
|
export class ItemDescriptor<T> {
|
||||||
constructor(public descriptor: IComponentDescriptor, public config: T) {}
|
constructor(public descriptor: IComponentDescriptor, public config: T) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class ComponentBase implements IComponent, OnDestroy, OnInit {
|
export abstract class ComponentBase extends Disposable implements IComponent, OnDestroy, OnInit {
|
||||||
protected properties: { [key: string]: any; } = {};
|
protected properties: { [key: string]: any; } = {};
|
||||||
constructor(
|
constructor (
|
||||||
protected _changeRef: ChangeDetectorRef) {
|
protected _changeRef: ChangeDetectorRef) {
|
||||||
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// IComponent implementation
|
/// IComponent implementation
|
||||||
|
|
||||||
abstract descriptor: IComponentDescriptor;
|
abstract descriptor: IComponentDescriptor;
|
||||||
abstract modelStore: IModelStore;
|
abstract modelStore: IModelStore;
|
||||||
|
protected _onEventEmitter = new Emitter<IComponentEventArgs>();
|
||||||
|
|
||||||
public layout(): void {
|
public layout(): void {
|
||||||
this._changeRef.detectChanges();
|
this._changeRef.detectChanges();
|
||||||
@@ -48,7 +52,9 @@ export abstract class ComponentBase implements IComponent, OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract ngOnDestroy(): void;
|
ngOnDestroy(): void {
|
||||||
|
this.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
abstract setLayout (layout: any): void;
|
abstract setLayout (layout: any): void;
|
||||||
|
|
||||||
@@ -68,6 +74,18 @@ export abstract class ComponentBase implements IComponent, OnDestroy, OnInit {
|
|||||||
let property = propertyGetter(this.getProperties<TPropertyBag>());
|
let property = propertyGetter(this.getProperties<TPropertyBag>());
|
||||||
return types.isUndefinedOrNull(property) ? defaultVal : property;
|
return types.isUndefinedOrNull(property) ? defaultVal : property;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected setProperty<TPropertyBag, TValue>(propertySetter: (TPropertyBag, TValue) => void, value: TValue) {
|
||||||
|
propertySetter(this.getProperties<TPropertyBag>(), value);
|
||||||
|
this._onEventEmitter.fire({
|
||||||
|
eventType: ComponentEventType.PropertiesChanged,
|
||||||
|
args: this.getProperties()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public get onEvent(): Event<IComponentEventArgs> {
|
||||||
|
return this._onEventEmitter.event;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class ContainerBase<T> extends ComponentBase {
|
export abstract class ContainerBase<T> extends ComponentBase {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
import FlexContainer from './flexContainer.component';
|
import FlexContainer from './flexContainer.component';
|
||||||
import CardComponent from './card.component';
|
import CardComponent from './card.component';
|
||||||
|
import InputBoxComponent from './inputbox.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';
|
||||||
|
|
||||||
@@ -13,3 +14,6 @@ registerComponentType(FLEX_CONTAINER, ModelComponentTypes.FlexContainer, FlexCon
|
|||||||
|
|
||||||
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';
|
||||||
|
registerComponentType(INPUTBOX_COMPONENT, ModelComponentTypes.InputBox, InputBoxComponent);
|
||||||
|
|||||||
96
src/sql/parts/modelComponents/inputbox.component.ts
Normal file
96
src/sql/parts/modelComponents/inputbox.component.ts
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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 { InputBox, IInputOptions } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||||
|
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||||
|
import { attachInputBoxStyler, attachListStyler } from 'vs/platform/theme/common/styler';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'inputBox',
|
||||||
|
template: `
|
||||||
|
<div #input style="width: 100%"></div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export default class InputBoxComponent extends ComponentBase implements IComponent, OnDestroy, AfterViewInit {
|
||||||
|
@Input() descriptor: IComponentDescriptor;
|
||||||
|
@Input() modelStore: IModelStore;
|
||||||
|
private _input: InputBox;
|
||||||
|
|
||||||
|
@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 inputOptions: IInputOptions = {
|
||||||
|
placeholder: '',
|
||||||
|
ariaLabel: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
this._input = new InputBox(this._inputContainer.nativeElement, this._commonService.contextViewService, inputOptions);
|
||||||
|
|
||||||
|
this._register(this._input);
|
||||||
|
this._register(attachInputBoxStyler(this._input, this._commonService.themeService));
|
||||||
|
this._register(this._input.onDidChange(e => {
|
||||||
|
this.value = this._input.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._input.value = this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSS-bound properties
|
||||||
|
|
||||||
|
public get value(): string {
|
||||||
|
return this.getPropertyOrDefault<sqlops.InputBoxProperties, string>((props) => props.value, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
public set value(newValue: string) {
|
||||||
|
this.setProperty<sqlops.InputBoxProperties, string>(this.setInputBoxProperties, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setInputBoxProperties(properties: sqlops.InputBoxProperties, value: string): void {
|
||||||
|
properties.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
import { InjectionToken } from '@angular/core';
|
import { InjectionToken } from '@angular/core';
|
||||||
|
|
||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
|
import Event, { Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instance of a model-backed component. This will be a UI element
|
* An instance of a model-backed component. This will be a UI element
|
||||||
@@ -20,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;
|
||||||
|
onEvent?: Event<IComponentEventArgs>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const COMPONENT_CONFIG = new InjectionToken<IComponentConfig>('component_config');
|
export const COMPONENT_CONFIG = new InjectionToken<IComponentConfig>('component_config');
|
||||||
@@ -48,6 +50,16 @@ export interface IComponentDescriptor {
|
|||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IComponentEventArgs {
|
||||||
|
eventType: ComponentEventType;
|
||||||
|
args: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ComponentEventType {
|
||||||
|
PropertiesChanged,
|
||||||
|
onDidChange
|
||||||
|
}
|
||||||
|
|
||||||
export interface IModelStore {
|
export interface IModelStore {
|
||||||
/**
|
/**
|
||||||
* Creates and saves the reference of a component descriptor.
|
* Creates and saves the reference of a component descriptor.
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ 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';
|
||||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||||
import { ModelStore } from 'sql/parts/modelComponents/modelStore';
|
import { ModelStore } from 'sql/parts/modelComponents/modelStore';
|
||||||
|
import Event, { Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
const componentRegistry = <IComponentRegistry> Registry.as(Extensions.ComponentContribution);
|
const componentRegistry = <IComponentRegistry> Registry.as(Extensions.ComponentContribution);
|
||||||
|
|
||||||
@@ -35,6 +36,8 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
|||||||
abstract id: string;
|
abstract id: string;
|
||||||
abstract connection: sqlops.connection.Connection;
|
abstract connection: sqlops.connection.Connection;
|
||||||
abstract serverInfo: sqlops.ServerInfo;
|
abstract serverInfo: sqlops.ServerInfo;
|
||||||
|
private _onEventEmitter = new Emitter<any>();
|
||||||
|
|
||||||
|
|
||||||
initializeModel(rootComponent: IComponentShape): void {
|
initializeModel(rootComponent: IComponentShape): void {
|
||||||
let descriptor = this.defineComponent(rootComponent);
|
let descriptor = this.defineComponent(rootComponent);
|
||||||
@@ -52,11 +55,13 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
|||||||
let descriptor = this.modelStore.createComponentDescriptor(typeId, component.id);
|
let descriptor = this.modelStore.createComponentDescriptor(typeId, component.id);
|
||||||
this.setProperties(component.id, component.properties);
|
this.setProperties(component.id, component.properties);
|
||||||
this.setLayout(component.id, component.layout);
|
this.setLayout(component.id, component.layout);
|
||||||
|
this.registerEvent(component.id);
|
||||||
if (component.itemConfigs) {
|
if (component.itemConfigs) {
|
||||||
for(let item of component.itemConfigs) {
|
for(let item of component.itemConfigs) {
|
||||||
this.addToContainer(component.id, item);
|
this.addToContainer(component.id, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,4 +96,18 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
|||||||
// TODO add error handling
|
// TODO add error handling
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerEvent(componentId: string) {
|
||||||
|
this.queueAction(componentId, (component) => {
|
||||||
|
if (component.onEvent) {
|
||||||
|
this._register(component.onEvent(e => {
|
||||||
|
this._onEventEmitter.fire(e);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public get onEvent(): Event<any> {
|
||||||
|
return this._onEventEmitter.event;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import * as sqlops from 'sqlops';
|
import * as sqlops from 'sqlops';
|
||||||
import { IItemConfig, IComponentShape } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { IItemConfig, IComponentShape } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
import Event, { Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
export interface IView {
|
export interface IView {
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
@@ -19,4 +20,6 @@ export interface IModelView extends IView {
|
|||||||
addToContainer(containerId: string, item: IItemConfig): void;
|
addToContainer(containerId: string, item: IItemConfig): void;
|
||||||
setLayout(componentId: string, layout: any): void;
|
setLayout(componentId: string, layout: any): void;
|
||||||
setProperties(componentId: string, properties: { [key: string]: any }): void;
|
setProperties(componentId: string, properties: { [key: string]: any }): void;
|
||||||
|
registerEvent(componentId: string);
|
||||||
|
onEvent: Event<any>;
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/sql/sqlops.proposed.d.ts
vendored
12
src/sql/sqlops.proposed.d.ts
vendored
@@ -19,6 +19,7 @@ declare module 'sqlops' {
|
|||||||
navContainer(): ContainerBuilder<NavContainer, any, any>;
|
navContainer(): ContainerBuilder<NavContainer, any, any>;
|
||||||
flexContainer(): FlexBuilder;
|
flexContainer(): FlexBuilder;
|
||||||
card(): ComponentBuilder<CardComponent>;
|
card(): ComponentBuilder<CardComponent>;
|
||||||
|
inputBox(): ComponentBuilder<InputBoxComponent>;
|
||||||
dashboardWidget(widgetId: string): ComponentBuilder<WidgetComponent>;
|
dashboardWidget(widgetId: string): ComponentBuilder<WidgetComponent>;
|
||||||
dashboardWebview(webviewId: string): ComponentBuilder<WebviewComponent>;
|
dashboardWebview(webviewId: string): ComponentBuilder<WebviewComponent>;
|
||||||
}
|
}
|
||||||
@@ -142,7 +143,7 @@ declare module 'sqlops' {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Properties representing the card component, can be used
|
* Properties representing the card component, can be used
|
||||||
* when using ModelBuilder to create the comopnent
|
* when using ModelBuilder to create the component
|
||||||
*/
|
*/
|
||||||
export interface CardProperties {
|
export interface CardProperties {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -150,12 +151,21 @@ declare module 'sqlops' {
|
|||||||
actions?: ActionDescriptor[];
|
actions?: ActionDescriptor[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InputBoxProperties {
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CardComponent extends Component {
|
export interface CardComponent extends Component {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
actions?: ActionDescriptor[];
|
actions?: ActionDescriptor[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InputBoxComponent extends Component {
|
||||||
|
value: string;
|
||||||
|
onTextChanged: vscode.Event<any>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface WidgetComponent extends Component {
|
export interface WidgetComponent extends Component {
|
||||||
widgetId: string;
|
widgetId: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ export enum ModelComponentTypes {
|
|||||||
NavContainer,
|
NavContainer,
|
||||||
FlexContainer,
|
FlexContainer,
|
||||||
Card,
|
Card,
|
||||||
|
InputBox,
|
||||||
DashboardWidget,
|
DashboardWidget,
|
||||||
DashboardWebview
|
DashboardWebview
|
||||||
}
|
}
|
||||||
@@ -83,3 +84,13 @@ export interface IItemConfig {
|
|||||||
componentShape: IComponentShape;
|
componentShape: IComponentShape;
|
||||||
config: any;
|
config: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ComponentEventType {
|
||||||
|
PropertiesChanged,
|
||||||
|
onDidChange
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IComponentEventArgs {
|
||||||
|
eventType: ComponentEventType;
|
||||||
|
args: any;
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,10 +13,11 @@ 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 } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { IItemConfig, ModelComponentTypes, IComponentShape, IComponentEventArgs, ComponentEventType } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
class ModelBuilderImpl implements sqlops.ModelBuilder {
|
class ModelBuilderImpl implements sqlops.ModelBuilder {
|
||||||
private nextComponentId: number;
|
private nextComponentId: number;
|
||||||
|
private readonly _eventHandlers = new Map<string, IWithEventHandler>();
|
||||||
|
|
||||||
constructor(private readonly _proxy: MainThreadModelViewShape, private readonly _handle: number) {
|
constructor(private readonly _proxy: MainThreadModelViewShape, private readonly _handle: number) {
|
||||||
this.nextComponentId = 0;
|
this.nextComponentId = 0;
|
||||||
@@ -34,17 +35,35 @@ class ModelBuilderImpl implements sqlops.ModelBuilder {
|
|||||||
|
|
||||||
card(): sqlops.ComponentBuilder<sqlops.CardComponent> {
|
card(): sqlops.ComponentBuilder<sqlops.CardComponent> {
|
||||||
let id = this.getNextComponentId();
|
let id = this.getNextComponentId();
|
||||||
return new ComponentBuilderImpl(new CardWrapper(this._proxy, this._handle, id));
|
return this.withEventHandler(new CardWrapper(this._proxy, this._handle, id), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
inputBox(): sqlops.ComponentBuilder<sqlops.InputBoxComponent> {
|
||||||
|
let id = this.getNextComponentId();
|
||||||
|
return this.withEventHandler(new InputBoxWrapper(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 new ComponentBuilderImpl<sqlops.WidgetComponent>(new ComponentWrapper(this._proxy, this._handle, ModelComponentTypes.DashboardWidget, id));
|
return this.withEventHandler<sqlops.WidgetComponent>(new ComponentWrapper(this._proxy, this._handle, ModelComponentTypes.DashboardWidget, id), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
dashboardWebview(webviewId: string): sqlops.ComponentBuilder<sqlops.WebviewComponent> {
|
dashboardWebview(webviewId: string): sqlops.ComponentBuilder<sqlops.WebviewComponent> {
|
||||||
let id = this.getNextComponentId();
|
let id = this.getNextComponentId();
|
||||||
return new ComponentBuilderImpl(new ComponentWrapper(this._proxy, this._handle, ModelComponentTypes.DashboardWebview, id));
|
return this.withEventHandler(new ComponentWrapper(this._proxy, this._handle, ModelComponentTypes.DashboardWebview, id), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
withEventHandler<T extends sqlops.Component>(component: ComponentWrapper, id: string): sqlops.ComponentBuilder<T> {
|
||||||
|
let componentBuilder: ComponentBuilderImpl<T> = new ComponentBuilderImpl<T>(component);
|
||||||
|
this._eventHandlers.set(id, componentBuilder);
|
||||||
|
return componentBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEvent(componentId: string, eventArgs: IComponentEventArgs): void {
|
||||||
|
let eventHandler = this._eventHandlers.get(componentId);
|
||||||
|
if (eventHandler) {
|
||||||
|
eventHandler.handleEvent(eventArgs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getNextComponentId(): string {
|
private getNextComponentId(): string {
|
||||||
@@ -52,9 +71,14 @@ class ModelBuilderImpl implements sqlops.ModelBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComponentBuilderImpl<T extends sqlops.Component> implements sqlops.ComponentBuilder<T> {
|
interface IWithEventHandler {
|
||||||
|
handleEvent(eventArgs: IComponentEventArgs): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ComponentBuilderImpl<T extends sqlops.Component> implements sqlops.ComponentBuilder<T>, IWithEventHandler {
|
||||||
|
|
||||||
constructor(protected _component: ComponentWrapper) {
|
constructor(protected _component: ComponentWrapper) {
|
||||||
|
_component.registerEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
component(): T {
|
component(): T {
|
||||||
@@ -65,6 +89,10 @@ class ComponentBuilderImpl<T extends sqlops.Component> implements sqlops.Compone
|
|||||||
this._component.properties = properties;
|
this._component.properties = properties;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleEvent(eventArgs: IComponentEventArgs) {
|
||||||
|
this._component.onEvent(eventArgs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GenericComponentBuilder<T extends sqlops.Component> extends ComponentBuilderImpl<T> {
|
class GenericComponentBuilder<T extends sqlops.Component> extends ComponentBuilderImpl<T> {
|
||||||
@@ -150,7 +178,6 @@ class ComponentWrapper implements sqlops.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public clearItems(): Thenable<void> {
|
public clearItems(): Thenable<void> {
|
||||||
this.itemConfigs = [];
|
this.itemConfigs = [];
|
||||||
return this._proxy.$clearContainer(this._handle, this.id);
|
return this._proxy.$clearContainer(this._handle, this.id);
|
||||||
@@ -184,6 +211,16 @@ class ComponentWrapper implements sqlops.Component {
|
|||||||
return this._proxy.$setProperties(this._handle, this._id, this.properties).then(() => true);
|
return this._proxy.$setProperties(this._handle, this._id, this.properties).then(() => true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public registerEvent(): Thenable<boolean> {
|
||||||
|
return this._proxy.$registerEvent(this._handle, this._id).then(() => true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onEvent(eventArgs: IComponentEventArgs) {
|
||||||
|
if (eventArgs && eventArgs.eventType === ComponentEventType.PropertiesChanged) {
|
||||||
|
this.properties = eventArgs.args;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected setProperty(key: string, value: any): Thenable<boolean> {
|
protected setProperty(key: string, value: any): Thenable<boolean> {
|
||||||
if (!this.properties[key] || this.properties[key] !== value) {
|
if (!this.properties[key] || this.properties[key] !== value) {
|
||||||
// Only notify the front end if a value has been updated
|
// Only notify the front end if a value has been updated
|
||||||
@@ -233,11 +270,45 @@ class CardWrapper extends ComponentWrapper implements sqlops.CardComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class InputBoxWrapper extends ComponentWrapper implements sqlops.InputBoxComponent {
|
||||||
|
|
||||||
|
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
|
||||||
|
super(proxy, handle, ModelComponentTypes.InputBox, id);
|
||||||
|
this.properties = {};
|
||||||
|
this._emitterMap.set(ComponentEventType.onDidChange, new Emitter<any>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private _onTextChangedEmitter = new Emitter<any>();
|
||||||
|
private _emitterMap = new Map<ComponentEventType, Emitter<any>>();
|
||||||
|
|
||||||
|
public get value(): string {
|
||||||
|
return this.properties['value'];
|
||||||
|
}
|
||||||
|
public set value(v: string) {
|
||||||
|
this.setProperty('value', v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get onTextChanged(): vscode.Event<any> {
|
||||||
|
let emitter = this._emitterMap.get(ComponentEventType.onDidChange);
|
||||||
|
return emitter && emitter.event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onEvent(eventArgs: IComponentEventArgs) {
|
||||||
|
super.onEvent(eventArgs);
|
||||||
|
if (eventArgs) {
|
||||||
|
let emitter = this._emitterMap.get(eventArgs.eventType);
|
||||||
|
if (emitter) {
|
||||||
|
emitter.fire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ModelViewImpl implements sqlops.ModelView {
|
class ModelViewImpl implements sqlops.ModelView {
|
||||||
|
|
||||||
public onClosedEmitter = new Emitter<any>();
|
public onClosedEmitter = new Emitter<any>();
|
||||||
|
|
||||||
private _modelBuilder: sqlops.ModelBuilder;
|
private _modelBuilder: ModelBuilderImpl;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _proxy: MainThreadModelViewShape,
|
private readonly _proxy: MainThreadModelViewShape,
|
||||||
@@ -264,6 +335,10 @@ class ModelViewImpl implements sqlops.ModelView {
|
|||||||
return this._modelBuilder;
|
return this._modelBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public handleEvent(componentId: string, eventArgs: IComponentEventArgs): void {
|
||||||
|
this._modelBuilder.handleEvent(componentId, eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
public initializeModel<T extends sqlops.Component>(component: T): Thenable<void> {
|
public initializeModel<T extends sqlops.Component>(component: T): Thenable<void> {
|
||||||
let componentImpl = <any>component as ComponentWrapper;
|
let componentImpl = <any>component as ComponentWrapper;
|
||||||
if (!componentImpl) {
|
if (!componentImpl) {
|
||||||
@@ -301,4 +376,11 @@ export class ExtHostModelView implements ExtHostModelViewShape {
|
|||||||
this._modelViews.set(handle, view);
|
this._modelViews.set(handle, view);
|
||||||
this._handlers.get(id)(view);
|
this._handlers.get(id)(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$handleEvent(handle: number, componentId: string, eventArgs: IComponentEventArgs): void {
|
||||||
|
const view = this._modelViews.get(handle);
|
||||||
|
if (view) {
|
||||||
|
view.handleEvent(componentId, eventArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,11 @@ import * as sqlops from 'sqlops';
|
|||||||
import { IModelViewService } from 'sql/services/modelComponents/modelViewService';
|
import { IModelViewService } from 'sql/services/modelComponents/modelViewService';
|
||||||
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 { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
|
|
||||||
@extHostNamedCustomer(SqlMainContext.MainThreadModelView)
|
@extHostNamedCustomer(SqlMainContext.MainThreadModelView)
|
||||||
export class MainThreadModelView implements MainThreadModelViewShape {
|
export class MainThreadModelView extends Disposable implements MainThreadModelViewShape {
|
||||||
|
|
||||||
private static _handlePool = 0;
|
private static _handlePool = 0;
|
||||||
private readonly _proxy: ExtHostModelViewShape;
|
private readonly _proxy: ExtHostModelViewShape;
|
||||||
@@ -28,6 +29,7 @@ export class MainThreadModelView implements MainThreadModelViewShape {
|
|||||||
context: IExtHostContext,
|
context: IExtHostContext,
|
||||||
@IModelViewService viewService: IModelViewService
|
@IModelViewService viewService: IModelViewService
|
||||||
) {
|
) {
|
||||||
|
super();
|
||||||
this._proxy = context.getProxy(SqlExtHostContext.ExtHostModelView);
|
this._proxy = context.getProxy(SqlExtHostContext.ExtHostModelView);
|
||||||
viewService.onRegisteredModelView(view => {
|
viewService.onRegisteredModelView(view => {
|
||||||
if (this.knownWidgets.includes(view.id)) {
|
if (this.knownWidgets.includes(view.id)) {
|
||||||
@@ -38,16 +40,14 @@ export class MainThreadModelView implements MainThreadModelViewShape {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
|
||||||
throw new Error('Method not implemented.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$registerProvider(id: string) {
|
$registerProvider(id: string) {
|
||||||
this.knownWidgets.push(id);
|
this.knownWidgets.push(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$initializeModel(handle: number, rootComponent: IComponentShape): Thenable<void> {
|
$initializeModel(handle: number, rootComponent: IComponentShape): Thenable<void> {
|
||||||
return this.execModelViewAction(handle, (modelView) => modelView.initializeModel(rootComponent));
|
return this.execModelViewAction(handle, (modelView) => {
|
||||||
|
modelView.initializeModel(rootComponent);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$clearContainer(handle: number, componentId: string): Thenable<void> {
|
$clearContainer(handle: number, componentId: string): Thenable<void> {
|
||||||
@@ -63,6 +63,19 @@ export class MainThreadModelView implements MainThreadModelViewShape {
|
|||||||
return this.execModelViewAction(handle, (modelView) => modelView.setLayout(componentId, layout));
|
return this.execModelViewAction(handle, (modelView) => modelView.setLayout(componentId, layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onEvent(handle: number, componentId: string, eventArgs: any) {
|
||||||
|
this._proxy.$handleEvent(handle, componentId, eventArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
$registerEvent(handle: number, componentId: string): Thenable<void> {
|
||||||
|
let properties: { [key: string]: any; } = { eventName: this.onEvent };
|
||||||
|
return this.execModelViewAction(handle, (modelView) => {
|
||||||
|
this._register(modelView.onEvent (e => {
|
||||||
|
this.onEvent(handle, componentId, e);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$setProperties(handle: number, componentId: string, properties: { [key: string]: any; }): Thenable<void> {
|
$setProperties(handle: number, componentId: string, properties: { [key: string]: any; }): Thenable<void> {
|
||||||
return this.execModelViewAction(handle, (modelView) => modelView.setProperties(componentId, properties));
|
return this.execModelViewAction(handle, (modelView) => modelView.setProperties(componentId, properties));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import * as vscode from 'vscode';
|
|||||||
|
|
||||||
import { ITaskHandlerDescription } from 'sql/platform/tasks/common/tasks';
|
import { ITaskHandlerDescription } from 'sql/platform/tasks/common/tasks';
|
||||||
import { IItemConfig, ModelComponentTypes, IComponentShape } from 'sql/workbench/api/common/sqlExtHostTypes';
|
import { IItemConfig, ModelComponentTypes, IComponentShape } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
import Event, { Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
export abstract class ExtHostAccountManagementShape {
|
export abstract class ExtHostAccountManagementShape {
|
||||||
$autoOAuthCancelled(handle: number): Thenable<void> { throw ni(); }
|
$autoOAuthCancelled(handle: number): Thenable<void> { throw ni(); }
|
||||||
@@ -514,6 +515,7 @@ export interface ExtHostModelViewShape {
|
|||||||
$registerProvider(widgetId: string, handler: (webview: sqlops.ModelView) => void): void;
|
$registerProvider(widgetId: string, handler: (webview: sqlops.ModelView) => void): void;
|
||||||
$onClosed(handle: number): void;
|
$onClosed(handle: number): void;
|
||||||
$registerWidget(handle: number, id: string, connection: sqlops.connection.Connection, serverInfo: sqlops.ServerInfo): void;
|
$registerWidget(handle: number, id: string, connection: sqlops.connection.Connection, serverInfo: sqlops.ServerInfo): void;
|
||||||
|
$handleEvent(handle: number, id: string, eventArgs: any);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MainThreadModelViewShape extends IDisposable {
|
export interface MainThreadModelViewShape extends IDisposable {
|
||||||
@@ -523,6 +525,7 @@ export interface MainThreadModelViewShape extends IDisposable {
|
|||||||
$addToContainer(handle: number, containerId: string, item: IItemConfig): Thenable<void>;
|
$addToContainer(handle: number, containerId: string, item: IItemConfig): Thenable<void>;
|
||||||
$setLayout(handle: number, componentId: string, layout: any): Thenable<void>;
|
$setLayout(handle: number, componentId: string, layout: any): Thenable<void>;
|
||||||
$setProperties(handle: number, componentId: string, properties: { [key: string]: any }): Thenable<void>;
|
$setProperties(handle: number, componentId: string, properties: { [key: string]: any }): Thenable<void>;
|
||||||
|
$registerEvent(handle: number, componentId: string): Thenable<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtHostObjectExplorerShape {
|
export interface ExtHostObjectExplorerShape {
|
||||||
|
|||||||
Reference in New Issue
Block a user