mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-13 17:22:15 -05:00
model view remove and insert components (#2351)
* added the ability to remove a component from a container to insert it to a position
This commit is contained in:
@@ -199,6 +199,7 @@ export default class MainController implements vscode.Disposable {
|
||||
dropdown.onValueChanged((params) => {
|
||||
vscode.window.showInformationMessage(inputBox2.value);
|
||||
inputBox.value = dropdown.value.toString();
|
||||
console.info('dropdown change ' + dropdown.value.toString());
|
||||
});
|
||||
let radioButton = view.modelBuilder.radioButton()
|
||||
.withProperties({
|
||||
@@ -231,14 +232,7 @@ export default class MainController implements vscode.Disposable {
|
||||
}).withItems([
|
||||
form2Model
|
||||
]).component();
|
||||
radioButton.onDidClick(() => {
|
||||
inputBox.value = radioButton.value;
|
||||
groupModel1.enabled = true;
|
||||
});
|
||||
radioButton2.onDidClick(() => {
|
||||
inputBox.value = radioButton.value;
|
||||
groupModel1.enabled = false;
|
||||
});
|
||||
|
||||
let table = view.modelBuilder.table().withProperties({
|
||||
data: [
|
||||
['1', '2', '2'],
|
||||
@@ -303,17 +297,12 @@ export default class MainController implements vscode.Disposable {
|
||||
}).withItems([
|
||||
radioButton, groupModel1, radioButton2]
|
||||
, { flex: '1 1 50%' }).component();
|
||||
let formModel = view.modelBuilder.formContainer()
|
||||
let formItemLayout = {
|
||||
horizontal: false,
|
||||
componentWidth: componentWidth
|
||||
};
|
||||
let formBuilder = view.modelBuilder.formContainer()
|
||||
.withFormItems([{
|
||||
component: inputBoxWrapper,
|
||||
title: 'Backup name'
|
||||
}, {
|
||||
component: inputBox2,
|
||||
title: 'Recovery model'
|
||||
}, {
|
||||
component: dropdown,
|
||||
title: 'Backup type'
|
||||
}, {
|
||||
component: checkbox,
|
||||
title: ''
|
||||
}, {
|
||||
@@ -326,16 +315,56 @@ export default class MainController implements vscode.Disposable {
|
||||
}, {
|
||||
component: declarativeTable,
|
||||
title: 'Declarative Table'
|
||||
}, {
|
||||
component: table,
|
||||
title: 'Table'
|
||||
}, {
|
||||
component: listBox,
|
||||
title: 'List Box'
|
||||
}], {
|
||||
horizontal: false,
|
||||
componentWidth: componentWidth
|
||||
}).component();
|
||||
}], formItemLayout);
|
||||
let groupItems = {
|
||||
components: [{
|
||||
component: table,
|
||||
title: 'Table'
|
||||
}, {
|
||||
component: listBox,
|
||||
title: 'List Box'
|
||||
}], title: 'group'};
|
||||
formBuilder.addFormItem(groupItems, formItemLayout);
|
||||
|
||||
formBuilder.insertFormItem({
|
||||
component: inputBoxWrapper,
|
||||
title: 'Backup name'
|
||||
}, 0, formItemLayout);
|
||||
formBuilder.insertFormItem({
|
||||
component: inputBox2,
|
||||
title: 'Recovery model'
|
||||
}, 1, formItemLayout);
|
||||
formBuilder.insertFormItem({
|
||||
component: dropdown,
|
||||
title: 'Backup type'
|
||||
}, 2, formItemLayout);
|
||||
let formModel = formBuilder.component();
|
||||
let inputBox6 = view.modelBuilder.inputBox().component();
|
||||
inputBox6.onTextChanged(e => {
|
||||
console.info('textbox6 changed: ' + inputBox6.value);
|
||||
});
|
||||
radioButton.onDidClick(() => {
|
||||
inputBox.value = radioButton.value;
|
||||
groupModel1.enabled = true;
|
||||
|
||||
formBuilder.insertFormItem({
|
||||
component: dropdown,
|
||||
title: 'Backup type'
|
||||
}, 2, formItemLayout);
|
||||
flexRadioButtonsModel.addItem(inputBox6, { flex: '1 1 50%' });
|
||||
formBuilder.addFormItem(groupItems, formItemLayout);
|
||||
});
|
||||
|
||||
radioButton2.onDidClick(() => {
|
||||
inputBox.value = radioButton.value;
|
||||
groupModel1.enabled = false;
|
||||
formBuilder.removeFormItem({
|
||||
component: dropdown,
|
||||
title: 'Backup type'
|
||||
});
|
||||
flexRadioButtonsModel.removeItem(inputBox6);
|
||||
formBuilder.removeFormItem(groupItems);
|
||||
});
|
||||
let formWrapper = view.modelBuilder.loadingComponent().withItem(formModel).component();
|
||||
formWrapper.loading = false;
|
||||
customButton2.onClick(() => {
|
||||
|
||||
@@ -91,10 +91,6 @@ export default class ButtonComponent extends ComponentWithIconBase implements IC
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
|
||||
@@ -81,10 +81,6 @@ export default class CardComponent extends ComponentWithIconBase implements ICom
|
||||
}
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout (layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
|
||||
@@ -63,10 +63,6 @@ export default class CheckBoxComponent extends ComponentBase implements ICompone
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
|
||||
@@ -21,6 +21,7 @@ import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentW
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { IdGenerator } from 'vs/base/common/idGenerator';
|
||||
import { createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom';
|
||||
import * as nls from 'vs/nls';
|
||||
|
||||
|
||||
export type IUserFriendlyIcon = string | URI | { light: string | URI; dark: string | URI };
|
||||
@@ -46,7 +47,9 @@ export abstract class ComponentBase extends Disposable implements IComponent, On
|
||||
protected _onEventEmitter = new Emitter<IComponentEventArgs>();
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
if (!this._changeRef['destroyed']) {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
protected baseInit(): void {
|
||||
@@ -222,17 +225,34 @@ export abstract class ContainerBase<T> extends ComponentBase {
|
||||
}
|
||||
|
||||
/// IComponent container-related implementation
|
||||
public addToContainer(componentDescriptor: IComponentDescriptor, config: any): void {
|
||||
public addToContainer(componentDescriptor: IComponentDescriptor, config: any, index?: number): void {
|
||||
if (this.items.some(item => item.descriptor.id === componentDescriptor.id && item.descriptor.type === componentDescriptor.type)) {
|
||||
return;
|
||||
}
|
||||
this.items.push(new ItemDescriptor(componentDescriptor, config));
|
||||
if (index !== undefined && index !== null && index >= 0 && index < this.items.length) {
|
||||
this.items.splice(index, 0, new ItemDescriptor(componentDescriptor, config));
|
||||
} else if(!index) {
|
||||
this.items.push(new ItemDescriptor(componentDescriptor, config));
|
||||
} else {
|
||||
throw new Error(nls.localize('invalidIndex', 'The index is invalid.'));
|
||||
}
|
||||
this.modelStore.eventuallyRunOnComponent(componentDescriptor.id, component => component.registerEventHandler(event => {
|
||||
if (event.eventType === ComponentEventType.validityChanged) {
|
||||
this.validate();
|
||||
}
|
||||
}));
|
||||
this._changeRef.detectChanges();
|
||||
return;
|
||||
}
|
||||
|
||||
public removeFromContainer(componentDescriptor: IComponentDescriptor): boolean {
|
||||
let index = this.items.findIndex(item => item.descriptor.id === componentDescriptor.id && item.descriptor.type === componentDescriptor.type);
|
||||
if (index >= 0) {
|
||||
this.items.splice(index, 1);
|
||||
this._changeRef.detectChanges();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public clearContainer(): void {
|
||||
|
||||
@@ -189,10 +189,6 @@ export default class DeclarativeTableComponent extends ComponentBase implements
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
|
||||
@@ -98,10 +98,6 @@ export default class DropDownComponent extends ComponentBase implements ICompone
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
|
||||
@@ -104,10 +104,6 @@ export default class FileBrowserTreeComponent extends ComponentBase implements I
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
|
||||
@@ -152,7 +152,7 @@ export default class InputBoxComponent extends ComponentBase implements ICompone
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
super.layout();
|
||||
this.layoutInputBox();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,14 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
* @export
|
||||
* @interface IComponent
|
||||
*/
|
||||
export interface IComponent {
|
||||
export interface IComponent extends IDisposable {
|
||||
descriptor: IComponentDescriptor;
|
||||
modelStore: IModelStore;
|
||||
layout();
|
||||
registerEventHandler(handler: (event: IComponentEventArgs) => void): IDisposable;
|
||||
clearContainer?: () => void;
|
||||
addToContainer?: (componentDescriptor: IComponentDescriptor, config: any) => void;
|
||||
addToContainer?: (componentDescriptor: IComponentDescriptor, config: any, index?: number) => void;
|
||||
removeFromContainer?: (componentDescriptor: IComponentDescriptor) => void;
|
||||
setLayout?: (layout: any) => void;
|
||||
setProperties?: (properties: { [key: string]: any; }) => void;
|
||||
enabled: boolean;
|
||||
|
||||
@@ -75,11 +75,6 @@ export default class ListBoxComponent extends ComponentBase implements IComponen
|
||||
}
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
|
||||
@@ -60,10 +60,6 @@ export default class LoadingComponent extends ComponentBase implements IComponen
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(): void {
|
||||
this.layout();
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ export class ModelStore implements IModelStore {
|
||||
let id = component.descriptor.id;
|
||||
this._componentMappings[id] = undefined;
|
||||
this._componentActions[id] = undefined;
|
||||
this._descriptorMappings[id] = undefined;
|
||||
// TODO notify model for cleanup
|
||||
}
|
||||
|
||||
|
||||
@@ -65,10 +65,6 @@ export default class RadioButtonComponent extends ComponentBase implements IComp
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
|
||||
@@ -132,8 +132,7 @@ export default class TableComponent extends ComponentBase implements IComponent,
|
||||
|
||||
public layout(): void {
|
||||
this.layoutTable();
|
||||
|
||||
this._changeRef.detectChanges();
|
||||
super.layout();
|
||||
}
|
||||
|
||||
private layoutTable(): void {
|
||||
|
||||
@@ -43,10 +43,6 @@ export default class TextComponent extends ComponentBase implements IComponent,
|
||||
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
}
|
||||
|
||||
public setLayout(layout: any): void {
|
||||
// TODO allow configuring the look and feel
|
||||
this.layout();
|
||||
|
||||
@@ -123,12 +123,11 @@ export default class TreeComponent extends ComponentBase implements IComponent,
|
||||
/// IComponent implementation
|
||||
|
||||
public layout(): void {
|
||||
this._changeRef.detectChanges();
|
||||
if (this._tree) {
|
||||
|
||||
this.layoutTree();
|
||||
this._tree.refresh();
|
||||
}
|
||||
super.layout();
|
||||
}
|
||||
|
||||
private layoutTree(): void {
|
||||
|
||||
@@ -71,15 +71,31 @@ export abstract class ViewBase extends AngularDisposable implements IModelView {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
private removeComponent(component: IComponentShape): void {
|
||||
if (component.itemConfigs) {
|
||||
for (let item of component.itemConfigs) {
|
||||
this.removeFromContainer(component.id, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearContainer(componentId: string): void {
|
||||
this.queueAction(componentId, (component) => component.clearContainer());
|
||||
}
|
||||
|
||||
addToContainer(containerId: string, itemConfig: IItemConfig): void {
|
||||
addToContainer(containerId: string, itemConfig: IItemConfig, index?: number): void {
|
||||
// Do not return the promise as this should be non-blocking
|
||||
this.queueAction(containerId, (component) => {
|
||||
let childDescriptor = this.defineComponent(itemConfig.componentShape);
|
||||
component.addToContainer(childDescriptor, itemConfig.config);
|
||||
component.addToContainer(childDescriptor, itemConfig.config, index);
|
||||
});
|
||||
}
|
||||
|
||||
removeFromContainer(containerId: string, itemConfig: IItemConfig): void {
|
||||
let childDescriptor = this.modelStore.getComponentDescriptor(itemConfig.componentShape.id);
|
||||
this.queueAction(containerId, (component) => {
|
||||
component.removeFromContainer(childDescriptor);
|
||||
this.removeComponent(itemConfig.componentShape);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ export interface IModelViewEventArgs extends IComponentEventArgs {
|
||||
export interface IModelView extends IView {
|
||||
initializeModel(rootComponent: IComponentShape, validationCallback?: (componentId: string) => Thenable<boolean>): void;
|
||||
clearContainer(componentId: string): void;
|
||||
addToContainer(containerId: string, item: IItemConfig): void;
|
||||
addToContainer(containerId: string, item: IItemConfig, index?: number): void;
|
||||
removeFromContainer(containerId: string, item: IItemConfig): void;
|
||||
setLayout(componentId: string, layout: any): void;
|
||||
setProperties(componentId: string, properties: { [key: string]: any }): void;
|
||||
setDataProvider(handle: number, componentId: string, context: any): void;
|
||||
|
||||
30
src/sql/sqlops.proposed.d.ts
vendored
30
src/sql/sqlops.proposed.d.ts
vendored
@@ -119,6 +119,20 @@ declare module 'sqlops' {
|
||||
* @param {*} [itemLayout] Optional layout for this child item
|
||||
*/
|
||||
addFormItem(formComponent: FormComponent | FormComponentGroup, itemLayout?: FormItemLayout): void;
|
||||
|
||||
/**
|
||||
* Inserts a from component in a given position in the form. Returns error given invalid index
|
||||
* @param formComponent Form component
|
||||
* @param index index to insert the component to
|
||||
* @param itemLayout Item Layout
|
||||
*/
|
||||
insertFormItem(formComponent: FormComponent | FormComponentGroup, index?: number, itemLayout?: FormItemLayout);
|
||||
|
||||
/**
|
||||
* Removes a from item from the from
|
||||
* @param formComponent
|
||||
*/
|
||||
removeFormItem(formComponent: FormComponent | FormComponentGroup): boolean;
|
||||
}
|
||||
|
||||
export interface Component {
|
||||
@@ -201,12 +215,28 @@ declare module 'sqlops' {
|
||||
|
||||
/**
|
||||
* Creates a child component and adds it to this container.
|
||||
* Adding component to multiple containers is not supported
|
||||
*
|
||||
* @param {Component} component the component to be added
|
||||
* @param {*} [itemLayout] Optional layout for this child item
|
||||
*/
|
||||
addItem(component: Component, itemLayout?: TItemLayout): void;
|
||||
|
||||
/**
|
||||
* Creates a child component and inserts it to this container. Returns error given invalid index
|
||||
* Adding component to multiple containers is not supported
|
||||
* @param component the component to be added
|
||||
* @param index the index to insert the component to
|
||||
* @param {*} [itemLayout] Optional layout for this child item
|
||||
*/
|
||||
insertItem(component: Component, index: number, itemLayout?: TItemLayout): void;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param component Removes a component from this container
|
||||
*/
|
||||
removeItem(component: Component): boolean;
|
||||
|
||||
/**
|
||||
* Defines the layout for this container
|
||||
*
|
||||
|
||||
@@ -305,6 +305,15 @@ class FormContainerBuilder extends ContainerBuilderImpl<sqlops.FormContainer, sq
|
||||
}
|
||||
}
|
||||
|
||||
private removeComponentActions(formComponent: sqlops.FormComponent): void {
|
||||
if (formComponent.actions) {
|
||||
formComponent.actions.forEach(component => {
|
||||
let componentWrapper = component as ComponentWrapper;
|
||||
this._component.removeItem(componentWrapper);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addFormItems(formComponents: Array<sqlops.FormComponent | sqlops.FormComponentGroup>, itemLayout?: sqlops.FormItemLayout): void {
|
||||
formComponents.forEach(formComponent => {
|
||||
this.addFormItem(formComponent, itemLayout);
|
||||
@@ -312,25 +321,56 @@ class FormContainerBuilder extends ContainerBuilderImpl<sqlops.FormContainer, sq
|
||||
}
|
||||
|
||||
addFormItem(formComponent: sqlops.FormComponent | sqlops.FormComponentGroup, itemLayout?: sqlops.FormItemLayout): void {
|
||||
this.insertFormItem(formComponent, undefined, itemLayout);
|
||||
}
|
||||
|
||||
insertFormItem(formComponent: sqlops.FormComponent | sqlops.FormComponentGroup, index?: number, itemLayout?: sqlops.FormItemLayout): void {
|
||||
let componentGroup = formComponent as sqlops.FormComponentGroup;
|
||||
if (componentGroup && componentGroup.components !== undefined) {
|
||||
let labelComponent = this._builder.text().component();
|
||||
labelComponent.value = componentGroup.title;
|
||||
this._component.addItem(labelComponent, { isGroupLabel: true });
|
||||
this._component.addItem(labelComponent, { isGroupLabel: true }, index);
|
||||
let componentIndex = index ? index + 1 : undefined;
|
||||
componentGroup.components.forEach(component => {
|
||||
let layout = component.layout || itemLayout;
|
||||
let itemConfig = this.convertToItemConfig(component, layout);
|
||||
itemConfig.config.isInGroup = true;
|
||||
this._component.addItem(component.component as ComponentWrapper, itemConfig.config);
|
||||
this._component.insertItem(component.component as ComponentWrapper, componentIndex, itemConfig.config);
|
||||
if (componentIndex) {
|
||||
componentIndex ++;
|
||||
}
|
||||
this.addComponentActions(component, layout);
|
||||
});
|
||||
} else {
|
||||
formComponent = formComponent as sqlops.FormComponent;
|
||||
let itemImpl = this.convertToItemConfig(formComponent, itemLayout);
|
||||
this._component.addItem(formComponent.component as ComponentWrapper, itemImpl.config);
|
||||
this._component.addItem(formComponent.component as ComponentWrapper, itemImpl.config, index);
|
||||
this.addComponentActions(formComponent, itemLayout);
|
||||
}
|
||||
}
|
||||
|
||||
removeFormItem(formComponent: sqlops.FormComponent | sqlops.FormComponentGroup): boolean {
|
||||
let componentGroup = formComponent as sqlops.FormComponentGroup;
|
||||
let result: boolean = false;
|
||||
if (componentGroup && componentGroup.components !== undefined) {
|
||||
let firstComponent = componentGroup.components[0];
|
||||
let index = this._component.itemConfigs.findIndex(x => x.component.id === firstComponent.component.id);
|
||||
if (index) {
|
||||
result = this._component.removeItemAt(index - 1);
|
||||
}
|
||||
componentGroup.components.forEach(element => {
|
||||
this.removeComponentActions(element);
|
||||
this._component.removeItem(element.component);
|
||||
});
|
||||
} else {
|
||||
formComponent = formComponent as sqlops.FormComponent;
|
||||
if (formComponent) {
|
||||
result = this._component.removeItem(formComponent.component as ComponentWrapper);
|
||||
this.removeComponentActions(formComponent);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class ToolbarContainerBuilder extends ContainerBuilderImpl<sqlops.ToolbarContainer, sqlops.ToolbarLayout, any> implements sqlops.ToolbarBuilder {
|
||||
@@ -470,14 +510,42 @@ class ComponentWrapper implements sqlops.Component {
|
||||
}
|
||||
}
|
||||
|
||||
public addItem(item: sqlops.Component, itemLayout?: any): void {
|
||||
public removeItemAt(index: number): boolean {
|
||||
if (index >= 0 && index < this.itemConfigs.length) {
|
||||
let itemConfig = this.itemConfigs[index];
|
||||
this._proxy.$removeFromContainer(this._handle, this.id, itemConfig.toIItemConfig());
|
||||
this.itemConfigs.splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public removeItem(item: sqlops.Component): boolean {
|
||||
let index = this.itemConfigs.findIndex(c => c.component.id === item.id);
|
||||
if (index >= 0 && index < this.itemConfigs.length) {
|
||||
return this.removeItemAt(index);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public insertItem(item: sqlops.Component, index: number, itemLayout?: any) {
|
||||
this.addItem(item, itemLayout, index);
|
||||
}
|
||||
|
||||
public addItem(item: sqlops.Component, itemLayout?: any, index?: number): void {
|
||||
let itemImpl = item as ComponentWrapper;
|
||||
if (!itemImpl) {
|
||||
throw new Error(nls.localize('unknownComponentType', 'Unkown component type. Must use ModelBuilder to create objects'));
|
||||
}
|
||||
let config = new InternalItemConfig(itemImpl, itemLayout);
|
||||
this.itemConfigs.push(config);
|
||||
this._proxy.$addToContainer(this._handle, this.id, config.toIItemConfig()).then(undefined, this.handleError);
|
||||
if (index !== undefined && index >= 0 && index < this.items.length) {
|
||||
this.itemConfigs.splice(index, 0, config);
|
||||
} else if (!index) {
|
||||
this.itemConfigs.push(config);
|
||||
} else {
|
||||
throw new Error(nls.localize('invalidIndex', 'The index is invalid.'));
|
||||
}
|
||||
this._proxy.$addToContainer(this._handle, this.id, config.toIItemConfig(), index).then(undefined, this.handleError);
|
||||
}
|
||||
|
||||
public setLayout(layout: any): Thenable<void> {
|
||||
|
||||
@@ -53,9 +53,14 @@ export class MainThreadModelView extends Disposable implements MainThreadModelVi
|
||||
return this.execModelViewAction(handle, (modelView) => modelView.clearContainer(componentId));
|
||||
}
|
||||
|
||||
$addToContainer(handle: number, containerId: string, item: IItemConfig): Thenable<void> {
|
||||
$addToContainer(handle: number, containerId: string, item: IItemConfig, index?: number): Thenable<void> {
|
||||
return this.execModelViewAction(handle,
|
||||
(modelView) => modelView.addToContainer(containerId, item));
|
||||
(modelView) => modelView.addToContainer(containerId, item, index));
|
||||
}
|
||||
|
||||
$removeFromContainer(handle: number, containerId: string, item: IItemConfig): Thenable<void> {
|
||||
return this.execModelViewAction(handle,
|
||||
(modelView) => modelView.removeFromContainer(containerId, item));
|
||||
}
|
||||
|
||||
$setLayout(handle: number, componentId: string, layout: any): Thenable<void> {
|
||||
|
||||
@@ -634,7 +634,8 @@ export interface MainThreadModelViewShape extends IDisposable {
|
||||
$registerProvider(id: string): void;
|
||||
$initializeModel(handle: number, rootComponent: IComponentShape): Thenable<void>;
|
||||
$clearContainer(handle: number, componentId: string): Thenable<void>;
|
||||
$addToContainer(handle: number, containerId: string, item: IItemConfig): Thenable<void>;
|
||||
$addToContainer(handle: number, containerId: string, item: IItemConfig, index?: number): Thenable<void>;
|
||||
$removeFromContainer(handle: number, containerId: string, item: IItemConfig): Thenable<void>;
|
||||
$setLayout(handle: number, componentId: string, layout: any): Thenable<void>;
|
||||
$setProperties(handle: number, componentId: string, properties: { [key: string]: any }): Thenable<void>;
|
||||
$registerEvent(handle: number, componentId: string): Thenable<void>;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Mock, It, Times, MockBehavior } from 'typemoq';
|
||||
import { ComponentBase, ContainerBase } from 'sql/parts/modelComponents/componentBase';
|
||||
import { ComponentBase, ContainerBase, ItemDescriptor } from 'sql/parts/modelComponents/componentBase';
|
||||
import { IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||
import { ModelStore } from 'sql/parts/modelComponents/modelStore';
|
||||
import { ChangeDetectorRef } from '@angular/core';
|
||||
@@ -41,6 +41,10 @@ class TestContainer extends ContainerBase<TestComponent> {
|
||||
this.baseInit();
|
||||
}
|
||||
|
||||
public get TestItems(): ItemDescriptor<TestComponent>[] {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
ngOnInit() { }
|
||||
setLayout() { }
|
||||
|
||||
@@ -51,12 +55,14 @@ class TestContainer extends ContainerBase<TestComponent> {
|
||||
|
||||
suite('ComponentBase Tests', () => {
|
||||
let testComponent: TestComponent;
|
||||
let testComponent2: TestComponent;
|
||||
let testContainer: TestContainer;
|
||||
let modelStore: IModelStore;
|
||||
|
||||
setup(() => {
|
||||
modelStore = new ModelStore();
|
||||
testComponent = new TestComponent(modelStore, 'testComponent');
|
||||
testComponent2 = new TestComponent(modelStore, 'testComponent2');
|
||||
testContainer = new TestContainer(modelStore, 'testContainer');
|
||||
});
|
||||
|
||||
@@ -130,6 +136,63 @@ suite('ComponentBase Tests', () => {
|
||||
testComponent.validate();
|
||||
});
|
||||
|
||||
test('Inserting a component to a container adds the component to the right place', done => {
|
||||
testContainer.addToContainer(testComponent.descriptor, undefined);
|
||||
assert.equal(testContainer.TestItems.length, 1);
|
||||
testContainer.addToContainer(testComponent2.descriptor, undefined, 0);
|
||||
assert.equal(testContainer.TestItems.length, 2);
|
||||
assert.equal(testContainer.TestItems[0].descriptor.id, testComponent2.descriptor.id);
|
||||
done();
|
||||
});
|
||||
|
||||
test('Inserting a component to a container given negative index fails', done => {
|
||||
testContainer.addToContainer(testComponent.descriptor, undefined);
|
||||
assert.equal(testContainer.TestItems.length, 1);
|
||||
assert.throws(() => testContainer.addToContainer(testComponent2.descriptor, undefined, -1));
|
||||
done();
|
||||
});
|
||||
|
||||
test('Inserting a component to a container given wrong index fails', done => {
|
||||
testContainer.addToContainer(testComponent.descriptor, undefined);
|
||||
assert.equal(testContainer.TestItems.length, 1);
|
||||
assert.throws(() => testContainer.addToContainer(testComponent2.descriptor, undefined, 10));
|
||||
done();
|
||||
});
|
||||
|
||||
test('Inserting a component to a container given end of list fails', done => {
|
||||
testContainer.addToContainer(testComponent.descriptor, undefined);
|
||||
assert.equal(testContainer.TestItems.length, 1);
|
||||
assert.throws(() => testContainer.addToContainer(testComponent2.descriptor, undefined, 1));
|
||||
done();
|
||||
});
|
||||
|
||||
test('Removing a component the does not exist does not make change in the items', done => {
|
||||
testContainer.addToContainer(testComponent.descriptor, undefined);
|
||||
assert.equal(testContainer.TestItems.length, 1);
|
||||
testContainer.removeFromContainer(testComponent2.descriptor);
|
||||
assert.equal(testContainer.TestItems.length, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
test('Removing a component removes it from items', done => {
|
||||
testContainer.addToContainer(testComponent.descriptor, undefined);
|
||||
testContainer.addToContainer(testComponent2.descriptor, undefined);
|
||||
assert.equal(testContainer.TestItems.length, 2);
|
||||
testContainer.removeFromContainer(testComponent.descriptor);
|
||||
assert.equal(testContainer.TestItems.length, 1);
|
||||
assert.equal(testContainer.TestItems[0].descriptor.id, testComponent2.descriptor.id);
|
||||
done();
|
||||
});
|
||||
|
||||
test('Container dost not add same component twice', done => {
|
||||
testContainer.addToContainer(testComponent.descriptor, undefined);
|
||||
assert.equal(testContainer.TestItems.length, 1);
|
||||
testContainer.addToContainer(testComponent.descriptor, 0);
|
||||
assert.equal(testContainer.TestItems.length, 1);
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
test('Component convert size should add px', done => {
|
||||
let expected = '100px';
|
||||
let actual = testComponent.convertSize(100);
|
||||
|
||||
@@ -14,6 +14,12 @@ import { IComponentShape, IItemConfig, ComponentEventType, IComponentEventArgs,
|
||||
import { TitledFormItemLayout } from 'sql/parts/modelComponents/formContainer.component';
|
||||
|
||||
'use strict';
|
||||
interface InternalItemConfig {
|
||||
toIItemConfig(): IItemConfig;
|
||||
}
|
||||
interface IWithItemConfig {
|
||||
itemConfigs?: InternalItemConfig[];
|
||||
}
|
||||
|
||||
suite('ExtHostModelView Validation Tests', () => {
|
||||
let extHostModelView: ExtHostModelView;
|
||||
@@ -33,6 +39,7 @@ suite('ExtHostModelView Validation Tests', () => {
|
||||
$initializeModel: (handle: number, rootComponent: IComponentShape) => undefined,
|
||||
$clearContainer: (handle: number, componentId: string) => undefined,
|
||||
$addToContainer: (handle: number, containerId: string, item: IItemConfig) => undefined,
|
||||
$removeFromContainer: (handle: number, containerId: string, item: IItemConfig) => undefined,
|
||||
$setLayout: (handle: number, componentId: string, layout: any) => undefined,
|
||||
$setProperties: (handle: number, componentId: string, properties: { [key: string]: any }) => undefined,
|
||||
$registerEvent: (handle: number, componentId: string) => undefined,
|
||||
@@ -132,7 +139,7 @@ suite('ExtHostModelView Validation Tests', () => {
|
||||
});
|
||||
|
||||
test('Setting a form component as required initializes the model with the component required', () => {
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), undefined)).returns(() => Promise.resolve());
|
||||
|
||||
// Set up the input component with required initially set to false
|
||||
let inputComponent = modelView.modelBuilder.inputBox().component();
|
||||
@@ -157,7 +164,7 @@ suite('ExtHostModelView Validation Tests', () => {
|
||||
// Set up the mock proxy to save the component that gets initialized so that it can be verified
|
||||
let rootComponent: IComponentShape;
|
||||
mockProxy.setup(x => x.$initializeModel(It.isAny(), It.isAny())).callback((handle, componentShape) => rootComponent = componentShape);
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), undefined)).returns(() => Promise.resolve());
|
||||
|
||||
// Set up the form with a top level component and a group
|
||||
let topLevelList = modelView.modelBuilder.listBox().component();
|
||||
@@ -213,4 +220,164 @@ suite('ExtHostModelView Validation Tests', () => {
|
||||
assert.equal((inputBoxConfig.config as sqlops.FormItemLayout).horizontal, groupInputLayout.horizontal);
|
||||
assert.equal((dropdownConfig.config as sqlops.FormItemLayout).horizontal, defaultLayout.horizontal);
|
||||
});
|
||||
|
||||
test('Inserting and removing components from a container should work correctly', () => {
|
||||
// Set up the mock proxy to save the component that gets initialized so that it can be verified
|
||||
let rootComponent: IComponentShape;
|
||||
mockProxy.setup(x => x.$initializeModel(It.isAny(), It.isAny())).callback((handle, componentShape) => rootComponent = componentShape);
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), undefined)).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$removeFromContainer(It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
|
||||
// Set up the form with a top level component and a group
|
||||
let listBox = modelView.modelBuilder.listBox().component();
|
||||
let inputBox = modelView.modelBuilder.inputBox().component();
|
||||
let dropDown = modelView.modelBuilder.dropDown().component();
|
||||
|
||||
let flex = modelView.modelBuilder.flexContainer().withItems([listBox, inputBox]).component();
|
||||
modelView.initializeModel(flex);
|
||||
|
||||
assert.equal((flex as IWithItemConfig).itemConfigs.length, 2);
|
||||
flex.insertItem(dropDown, 1);
|
||||
assert.equal((flex as IWithItemConfig).itemConfigs.length, 3);
|
||||
assert.equal((flex as IWithItemConfig).itemConfigs[1].toIItemConfig().componentShape.type, ModelComponentTypes.DropDown);
|
||||
flex.removeItem(listBox);
|
||||
assert.equal((flex as IWithItemConfig).itemConfigs.length, 2);
|
||||
assert.equal((flex as IWithItemConfig).itemConfigs[0].toIItemConfig().componentShape.type, ModelComponentTypes.DropDown);
|
||||
});
|
||||
|
||||
test('Inserting component give negative number fails', () => {
|
||||
// Set up the mock proxy to save the component that gets initialized so that it can be verified
|
||||
let rootComponent: IComponentShape;
|
||||
mockProxy.setup(x => x.$initializeModel(It.isAny(), It.isAny())).callback((handle, componentShape) => rootComponent = componentShape);
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), undefined)).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$removeFromContainer(It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
|
||||
// Set up the form with a top level component and a group
|
||||
let listBox = modelView.modelBuilder.listBox().component();
|
||||
let inputBox = modelView.modelBuilder.inputBox().component();
|
||||
let dropDown = modelView.modelBuilder.dropDown().component();
|
||||
|
||||
let flex = modelView.modelBuilder.flexContainer().withItems([listBox, inputBox]).component();
|
||||
modelView.initializeModel(flex);
|
||||
|
||||
assert.equal((flex as IWithItemConfig).itemConfigs.length, 2);
|
||||
assert.throws(() => flex.insertItem(dropDown, -1));
|
||||
});
|
||||
|
||||
test('Inserting component give wrong number fails', () => {
|
||||
// Set up the mock proxy to save the component that gets initialized so that it can be verified
|
||||
let rootComponent: IComponentShape;
|
||||
mockProxy.setup(x => x.$initializeModel(It.isAny(), It.isAny())).callback((handle, componentShape) => rootComponent = componentShape);
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), undefined)).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$removeFromContainer(It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
|
||||
// Set up the form with a top level component and a group
|
||||
let listBox = modelView.modelBuilder.listBox().component();
|
||||
let inputBox = modelView.modelBuilder.inputBox().component();
|
||||
let dropDown = modelView.modelBuilder.dropDown().component();
|
||||
|
||||
let flex = modelView.modelBuilder.flexContainer().withItems([listBox, inputBox]).component();
|
||||
modelView.initializeModel(flex);
|
||||
|
||||
assert.equal((flex as IWithItemConfig).itemConfigs.length, 2);
|
||||
assert.throws(() => flex.insertItem(dropDown, 10));
|
||||
});
|
||||
|
||||
test('Inserting component give end of the list fails', () => {
|
||||
// Set up the mock proxy to save the component that gets initialized so that it can be verified
|
||||
let rootComponent: IComponentShape;
|
||||
mockProxy.setup(x => x.$initializeModel(It.isAny(), It.isAny())).callback((handle, componentShape) => rootComponent = componentShape);
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), undefined)).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$removeFromContainer(It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
|
||||
// Set up the form with a top level component and a group
|
||||
let listBox = modelView.modelBuilder.listBox().component();
|
||||
let inputBox = modelView.modelBuilder.inputBox().component();
|
||||
let dropDown = modelView.modelBuilder.dropDown().component();
|
||||
|
||||
let flex = modelView.modelBuilder.flexContainer().withItems([listBox, inputBox]).component();
|
||||
modelView.initializeModel(flex);
|
||||
|
||||
assert.equal((flex as IWithItemConfig).itemConfigs.length, 2);
|
||||
assert.throws(() => flex.insertItem(dropDown, 2));
|
||||
});
|
||||
|
||||
test('Removing a component that does not exist does not fail', () => {
|
||||
// Set up the mock proxy to save the component that gets initialized so that it can be verified
|
||||
let rootComponent: IComponentShape;
|
||||
mockProxy.setup(x => x.$initializeModel(It.isAny(), It.isAny())).callback((handle, componentShape) => rootComponent = componentShape);
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), undefined)).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
|
||||
// Set up the form with a top level component and a group
|
||||
let listBox = modelView.modelBuilder.listBox().component();
|
||||
let inputBox = modelView.modelBuilder.inputBox().component();
|
||||
let dropDown = modelView.modelBuilder.dropDown().component();
|
||||
|
||||
let flex = modelView.modelBuilder.flexContainer().withItems([listBox, inputBox]).component();
|
||||
modelView.initializeModel(flex);
|
||||
|
||||
let result = flex.removeItem(dropDown);
|
||||
assert.equal(result, false);
|
||||
assert.equal((flex as IWithItemConfig).itemConfigs.length, 2);
|
||||
assert.equal((flex as IWithItemConfig).itemConfigs[0].toIItemConfig().componentShape.type, ModelComponentTypes.ListBox);
|
||||
});
|
||||
|
||||
|
||||
test('Inserting and removing component in a form should work correctly', () => {
|
||||
// Set up the mock proxy to save the component that gets initialized so that it can be verified
|
||||
let rootComponent: IComponentShape;
|
||||
mockProxy.setup(x => x.$initializeModel(It.isAny(), It.isAny())).callback((handle, componentShape) => rootComponent = componentShape);
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), undefined)).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$addToContainer(It.isAny(), It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
mockProxy.setup(x => x.$removeFromContainer(It.isAny(), It.isAny(), It.isAny())).returns(() => Promise.resolve());
|
||||
|
||||
// Set up the form with a top level component and a group
|
||||
let listBox = modelView.modelBuilder.listBox().component();
|
||||
let inputBox = modelView.modelBuilder.inputBox().component();
|
||||
let dropDown = modelView.modelBuilder.dropDown().component();
|
||||
let checkBox = modelView.modelBuilder.checkBox().component();
|
||||
|
||||
let groupItems: sqlops.FormComponentGroup = {
|
||||
title: 'Group',
|
||||
components: [{
|
||||
title: 'Drop Down',
|
||||
component: dropDown
|
||||
}, {
|
||||
title: 'Check Box',
|
||||
component: checkBox
|
||||
}]
|
||||
};
|
||||
let listBoxFormItem: sqlops.FormComponent = {
|
||||
title: 'List Box',
|
||||
component: listBox
|
||||
};
|
||||
let inputBoxFormItem: sqlops.FormComponent = {
|
||||
title: 'Input Box',
|
||||
component: inputBox
|
||||
};
|
||||
|
||||
let formBuilder = modelView.modelBuilder.formContainer();
|
||||
formBuilder.addFormItem(listBoxFormItem);
|
||||
let form = formBuilder.component();
|
||||
modelView.initializeModel(formBuilder.component());
|
||||
|
||||
assert.equal((form as IWithItemConfig).itemConfigs.length, 1);
|
||||
formBuilder.insertFormItem(inputBoxFormItem, 0);
|
||||
assert.equal((form as IWithItemConfig).itemConfigs.length, 2);
|
||||
assert.equal((form as IWithItemConfig).itemConfigs[0].toIItemConfig().componentShape.type, ModelComponentTypes.InputBox);
|
||||
formBuilder.insertFormItem(groupItems, 0);
|
||||
assert.equal((form as IWithItemConfig).itemConfigs.length, 5);
|
||||
formBuilder.removeFormItem(listBoxFormItem);
|
||||
assert.equal((form as IWithItemConfig).itemConfigs.length, 4);
|
||||
formBuilder.removeFormItem(groupItems);
|
||||
assert.equal((form as IWithItemConfig).itemConfigs.length, 1);
|
||||
formBuilder.addFormItem(listBoxFormItem);
|
||||
assert.equal((form as IWithItemConfig).itemConfigs.length, 2);
|
||||
assert.equal((form as IWithItemConfig).itemConfigs[1].toIItemConfig().componentShape.type, ModelComponentTypes.ListBox);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user