diff --git a/src/sql/azdata.proposed.d.ts b/src/sql/azdata.proposed.d.ts index 36b12a6c0a..6645455619 100644 --- a/src/sql/azdata.proposed.d.ts +++ b/src/sql/azdata.proposed.d.ts @@ -1104,7 +1104,7 @@ declare module 'azdata' { } /** - * The table designer view definition + * The table designer view definition. */ export interface TableDesignerView { /** @@ -1141,11 +1141,11 @@ declare module 'azdata' { } /** - * The definition of a designer tab + * The definition of a designer tab. */ export interface DesignerTab { /** - * The title of the tab + * The title of the tab. */ title: string; /** @@ -1159,22 +1159,25 @@ declare module 'azdata' { */ export interface DesignerDataPropertyInfo { /** - * The property name + * The property name. */ propertyName: string; - /** - * The description of the property + * The description of the property. */ description?: string; /** - * The component type + * The component type. */ componentType: DesignerComponentTypeName; /** * The group name, properties with the same group name will be displayed under the same group on the UI. */ group?: string; + /** + * Whether the property should be displayed in the properties view. The default value is true. + */ + showInPropertiesView?: boolean; /** * The properties of the component. */ @@ -1196,12 +1199,12 @@ declare module 'azdata' { columns?: string[]; /** - * The display name of the object type + * The display name of the object type. */ objectTypeDisplayName: string; /** - * the properties of the table data item + * the properties of the table data item. */ itemProperties?: DesignerDataPropertyInfo[]; @@ -1233,15 +1236,15 @@ declare module 'azdata' { */ export enum DesignerEditType { /** - * Add a row to a table + * Add a row to a table. */ Add = 0, /** - * Remove a row from a table + * Remove a row from a table. */ Remove = 1, /** - * Update a property + * Update a property. */ Update = 2 } @@ -1251,23 +1254,35 @@ declare module 'azdata' { */ export interface DesignerEdit { /** - * The edit type + * The edit type. */ type: DesignerEditType; /** - * the property that was edited + * the path of the edit target. */ - property: DesignerEditIdentifier; + path: DesignerEditPath; /** - * the new value + * the new value. */ value?: any; } /** - * The identifier of a property. The value is string typed if the property belongs to the root object, otherwise the type of the value is an object. + * The path of the edit target. + * Below are the 3 scenarios and their expected path. + * Note: 'index-{x}' in the description below are numbers represent the index of the object in the list. + * 1. 'Add' scenario + * a. ['propertyName1']. Example: add a column to the columns property: ['columns']. + * b. ['propertyName1',index-1,'propertyName2']. Example: add a column mapping to the first foreign key: ['foreignKeys',0,'mappings']. + * 2. 'Update' scenario + * a. ['propertyName1']. Example: update the name of the table: ['name']. + * b. ['propertyName1',index-1,'propertyName2']. Example: update the name of a column: ['columns',0,'name']. + * c. ['propertyName1',index-1,'propertyName2',index-2,'propertyName3']. Example: update the source column of an entry in a foreign key's column mapping table: ['foreignKeys',0,'mappings',0,'source']. + * 3. 'Remove' scenario + * a. ['propertyName1',index-1]. Example: remove a column from the columns property: ['columns',0']. + * b. ['propertyName1',index-1,'propertyName2',index-2]. Example: remove a column mapping from a foreign key's column mapping table: ['foreignKeys',0,'mappings',0]. */ - export type DesignerEditIdentifier = string | { parentProperty: string, index: number, property: string }; + export type DesignerEditPath = (string | number)[]; /** * The result returned by the table designer provider after handling an edit request. @@ -1284,7 +1299,7 @@ declare module 'azdata' { /** * Error messages of current state, and the property the caused the error. */ - errors?: { message: string, property?: DesignerEditIdentifier }[]; + errors?: { message: string, property?: DesignerEditPath }[]; } } } diff --git a/src/sql/workbench/browser/designer/designer.ts b/src/sql/workbench/browser/designer/designer.ts index df82ee8696..92924251de 100644 --- a/src/sql/workbench/browser/designer/designer.ts +++ b/src/sql/workbench/browser/designer/designer.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { - DesignerComponentInput, DesignerEditType, DesignerTab, DesignerEdit, DesignerEditIdentifier, DesignerViewModel, DesignerDataPropertyInfo, - DesignerTableComponentRowData, DesignerTableProperties, InputBoxProperties, DropDownProperties, CheckBoxProperties, DesignerComponentTypeName, - DesignerEditProcessedEventArgs, DesignerStateChangedEventArgs, DesignerAction, DesignerUIState, DesignerTextEditor, ScriptProperty + DesignerComponentInput, DesignerEditType, DesignerTab, DesignerEdit, DesignerEditPath, DesignerViewModel, DesignerDataPropertyInfo, + DesignerTableComponentRowData, DesignerTableProperties, InputBoxProperties, DropDownProperties, CheckBoxProperties, + DesignerEditProcessedEventArgs, DesignerStateChangedEventArgs, DesignerAction, DesignerUIState, DesignerTextEditor, ScriptProperty, DesignerRootObjectPath } from 'sql/workbench/browser/designer/interfaces'; import { IPanelTab, ITabbedPanelStyles, TabbedPanel } from 'sql/base/browser/ui/panel/panel'; @@ -26,7 +26,7 @@ import { localize } from 'vs/nls'; import { TableCellEditorFactory } from 'sql/base/browser/ui/table/tableCellEditorFactory'; import { CheckBoxColumn } from 'sql/base/browser/ui/table/plugins/checkboxColumn.plugin'; import { DesignerTabPanelView } from 'sql/workbench/browser/designer/designerTabPanelView'; -import { DesignerPropertiesPane, PropertiesPaneObjectContext } from 'sql/workbench/browser/designer/designerPropertiesPane'; +import { DesignerPropertiesPane } from 'sql/workbench/browser/designer/designerPropertiesPane'; import { Button, IButtonStyles } from 'sql/base/browser/ui/button/button'; import { ButtonColumn } from 'sql/base/browser/ui/table/plugins/buttonColumn.plugin'; import { Codicon } from 'vs/base/common/codicons'; @@ -35,6 +35,7 @@ import { LoadingSpinner } from 'sql/base/browser/ui/loadingSpinner/loadingSpinne import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { DesignerScriptEditor } from 'sql/workbench/browser/designer/designerScriptEditor'; +import { INotificationService } from 'vs/platform/notification/common/notification'; export interface IDesignerStyle { tabbedPanelStyles?: ITabbedPanelStyles; @@ -49,9 +50,12 @@ export interface IDesignerStyle { export type DesignerUIComponent = InputBox | Checkbox | Table | SelectBox; -export type CreateComponentsFunc = (container: HTMLElement, components: DesignerDataPropertyInfo[], editIdentifierGetter: (property: DesignerDataPropertyInfo) => DesignerEditIdentifier) => DesignerUIComponent[]; +export type CreateComponentsFunc = (container: HTMLElement, components: DesignerDataPropertyInfo[], parentPath: DesignerEditPath) => DesignerUIComponent[]; export type SetComponentValueFunc = (definition: DesignerDataPropertyInfo, component: DesignerUIComponent, data: DesignerViewModel) => void; +const TableRowHeight = 23; +const TableHeaderRowHeight = 28; + export class Designer extends Disposable implements IThemable { private _loadingSpinner: LoadingSpinner; private _horizontalSplitViewContainer: HTMLElement; @@ -78,21 +82,18 @@ export class Designer extends Disposable implements IThemable { constructor(private readonly _container: HTMLElement, @IInstantiationService private readonly _instantiationService: IInstantiationService, - @IContextViewService private readonly _contextViewProvider: IContextViewService) { + @IContextViewService private readonly _contextViewProvider: IContextViewService, + @INotificationService private readonly _notificationService: INotificationService) { super(); this._tableCellEditorFactory = new TableCellEditorFactory( { valueGetter: (item, column): string => { return item[column.field].value; }, - valueSetter: (context: string, row: number, item: DesignerTableComponentRowData, column: Slick.Column, value: string): void => { + valueSetter: (parentPath: DesignerEditPath, row: number, item: DesignerTableComponentRowData, column: Slick.Column, value: string): void => { this.handleEdit({ type: DesignerEditType.Update, - property: { - parentProperty: context, - index: row, - property: column.field - }, + path: [...parentPath, row, column.field], value: value }); }, @@ -150,14 +151,16 @@ export class Designer extends Disposable implements IThemable { this._horizontalSplitView.addView({ element: this._propertiesPaneContainer, - layout: size => { }, + layout: size => { + this.layoutPropertiesPane(); + }, minimumSize: 200, maximumSize: Number.POSITIVE_INFINITY, onDidChange: Event.None }, Sizing.Distribute); - this._propertiesPane = new DesignerPropertiesPane(this._propertiesPaneContainer, (container, components, identifierGetter) => { - return this.createComponents(container, components, this._propertiesPane.componentMap, this._propertiesPane.groupHeaders, identifierGetter, false, true); + this._propertiesPane = new DesignerPropertiesPane(this._propertiesPaneContainer, (container, components, parentPath) => { + return this.createComponents(container, components, this._propertiesPane.componentMap, this._propertiesPane.groupHeaders, parentPath, false, false); }, (definition, component, viewModel) => { this.setComponentValue(definition, component, viewModel); }); @@ -272,13 +275,14 @@ export class Designer extends Disposable implements IThemable { private initializeDesigner(): void { const view = this._input.view; if (view.components) { - this.createComponents(this._topContentContainer, view.components, this._componentMap, this._groupHeaders, component => component.propertyName, true, false); + this.createComponents(this._topContentContainer, view.components, this._componentMap, this._groupHeaders, DesignerRootObjectPath, true, true); } view.tabs.forEach(tab => { this._tabbedPanel.pushTab(this.createTabView(tab)); }); this.layoutTabbedPanel(); this.updateComponentValues(); + this.updatePropertiesPane(DesignerRootObjectPath); this.restoreUIState(); } @@ -287,17 +291,26 @@ export class Designer extends Disposable implements IThemable { const result = args.result; if (result.isValid) { this._supressEditProcessing = true; - this.updateComponentValues(); - if (edit.type === DesignerEditType.Add) { - // Move focus to the first cell of the newly added row. - const propertyName = edit.property as string; - const tableData = this._input.viewModel[propertyName] as DesignerTableProperties; - const table = this._componentMap.get(propertyName).component as Table; - table.setActiveCell(tableData.data.length - 1, 0); + try { + this.updateComponentValues(); + if (edit.type === DesignerEditType.Add) { + // For tables in the main view, move focus to the first cell of the newly added row, and the properties pane will be showing the new object. + if (edit.path.length === 1) { + const propertyName = edit.path[0] as string; + const tableData = this._input.viewModel[propertyName] as DesignerTableProperties; + const table = this._componentMap.get(propertyName).component as Table; + table.setActiveCell(tableData.data.length - 1, 0); + } + } else if (edit.type === DesignerEditType.Update) { + // for edit, update the properties pane with new values of current object. + this.updatePropertiesPane(this._propertiesPane.objectPath); + } + } catch (err) { + this._notificationService.error(err); } this._supressEditProcessing = false; } else { - //TODO: add error notification + this._notificationService.error(result.errors.map(e => e.message)); } } @@ -340,39 +353,53 @@ export class Designer extends Disposable implements IThemable { this._tabbedPanel.layout(new DOM.Dimension(this._tabbedPanelContainer.clientWidth, this._tabbedPanelContainer.clientHeight)); } - private updatePropertiesPane(newContext: PropertiesPaneObjectContext): void { - const viewModel = this._input.viewModel; + private layoutPropertiesPane() { + this._propertiesPane?.componentMap.forEach((v) => { + if (v.component instanceof Table) { + const rows = v.component.getData().getLength(); + // Tables in properties pane, minimum height:2 rows, maximum height: 10 rows. + const actualHeight = this.getTableHeight(rows); + const minHeight = this.getTableHeight(2); + const maxHeight = this.getTableHeight(10); + const height = Math.min(Math.max(minHeight, actualHeight), maxHeight); + v.component.layout(new DOM.Dimension(this._propertiesPaneContainer.clientWidth - 10 /*padding*/, height)); + } + }); + } + + private getTableHeight(rows: number): number { + return rows * TableRowHeight + TableHeaderRowHeight; + } + + private updatePropertiesPane(objectPath: DesignerEditPath): void { let type: string; let components: DesignerDataPropertyInfo[]; - let inputViewModel: DesignerViewModel; - let context: PropertiesPaneObjectContext; - if (newContext !== 'root') { - context = newContext; - const tableData = viewModel[newContext.parentProperty] as DesignerTableProperties; - const tableProperties = this._componentMap.get(newContext.parentProperty).defintion.componentProperties as DesignerTableProperties; - inputViewModel = tableData.data[newContext.index] as DesignerViewModel; + let objectViewModel: DesignerViewModel; + if (objectPath.length === 0) { // root object + type = this._input.objectTypeDisplayName; + components = []; + components.push(...this._input.view.components); + this._input.view.tabs.forEach(tab => { + components.push(...tab.components); + }); + objectViewModel = this._input.viewModel; + } else if (objectPath.length === 2) { // second level object + const parentPropertyName = objectPath[0] as string; + const objectIndex = objectPath[1] as number; + const tableData = this._input.viewModel[parentPropertyName] as DesignerTableProperties; + const tableProperties = this._componentMap.get(parentPropertyName).defintion.componentProperties as DesignerTableProperties; + objectViewModel = tableData.data[objectIndex] as DesignerViewModel; components = tableProperties.itemProperties; type = tableProperties.objectTypeDisplayName; } - if (!inputViewModel) { - context = 'root'; - components = []; - this._componentMap.forEach(value => { - components.push(value.defintion); - }); - type = this._input.objectTypeDisplayName; - inputViewModel = viewModel; - } - - if (inputViewModel) { - this._propertiesPane.show({ - context: context, - type: type, - components: components, - viewModel: inputViewModel - }); - } + this._propertiesPane.show({ + path: objectPath, + type: type, + components: components, + viewModel: objectViewModel + }); + this.layoutPropertiesPane(); } private updateComponentValues(): void { @@ -384,65 +411,18 @@ export class Designer extends Disposable implements IThemable { this._componentMap.forEach((value) => { this.setComponentValue(value.defintion, value.component, viewModel); }); - this.updatePropertiesPane(this._propertiesPane.context ?? 'root'); } private handleEdit(edit: DesignerEdit): void { if (this._supressEditProcessing) { return; } - this.applyEdit(edit); this._input.processEdit(edit); } - private applyEdit(edit: DesignerEdit): void { - const viewModel = this._input.viewModel; - switch (edit.type) { - case DesignerEditType.Update: - if (typeof edit.property === 'string') { - // if the type of the property is string then the property is a top level property - if (!viewModel[edit.property]) { - viewModel[edit.property] = {}; - } - const componentData = viewModel[edit.property]; - const componentType = this._componentMap.get(edit.property).defintion.componentType; - this.setComponentData(componentType, componentData, edit.value); - } else { - const columnPropertyName = edit.property.property; - const tableInfo = this._componentMap.get(edit.property.parentProperty).defintion.componentProperties as DesignerTableProperties; - const tableProperties = viewModel[edit.property.parentProperty] as DesignerTableProperties; - if (!tableProperties.data[edit.property.index][columnPropertyName]) { - tableProperties.data[edit.property.index][columnPropertyName] = {}; - } - const componentData = tableProperties.data[edit.property.index][columnPropertyName]; - const itemProperty = tableInfo.itemProperties.find(property => property.propertyName === columnPropertyName); - if (itemProperty) { - this.setComponentData(itemProperty.componentType, componentData, edit.value); - } - } - break; - default: - break; - } - } - - private setComponentData(componentType: DesignerComponentTypeName, componentData: any, value: any): void { - switch (componentType) { - case 'checkbox': - (componentData).checked = value; - break; - case 'dropdown': - (componentData).value = value; - break; - case 'input': - (componentData).value = value; - break; - } - } - private createTabView(tab: DesignerTab): IPanelTab { const view = new DesignerTabPanelView(tab, (container, components, identifierGetter) => { - return this.createComponents(container, components, this._componentMap, this._groupHeaders, identifierGetter, true, false); + return this.createComponents(container, components, this._componentMap, this._groupHeaders, identifierGetter, true, true); }); return { identifier: tab.title, @@ -517,11 +497,11 @@ export class Designer extends Disposable implements IThemable { components: DesignerDataPropertyInfo[], componentMap: Map, groupHeaders: HTMLElement[], - identifierGetter: (definition: DesignerDataPropertyInfo) => DesignerEditIdentifier, - setWidth: boolean, skipTableCreation: boolean = false): DesignerUIComponent[] { + parentPath: DesignerEditPath, + setWidth: boolean, isMainView: boolean): DesignerUIComponent[] { const uiComponents = []; const groupNames = []; - const componentsToCreate = skipTableCreation ? components.filter(component => component.componentType !== 'table') : components; + const componentsToCreate = !isMainView ? components.filter(component => component.showInPropertiesView !== false) : components; componentsToCreate.forEach(component => { if (groupNames.indexOf(component.group) === -1) { groupNames.push(component.group); @@ -531,7 +511,7 @@ export class Designer extends Disposable implements IThemable { // only show groups when there are multiple of them. if (groupNames.length < 2) { componentsToCreate.forEach(component => { - uiComponents.push(this.createComponent(container, component, identifierGetter(component), componentMap, setWidth)); + uiComponents.push(this.createComponent(container, component, parentPath, componentMap, setWidth, isMainView)); }); } else { groupNames.forEach(group => { @@ -541,7 +521,7 @@ export class Designer extends Disposable implements IThemable { groupHeader.innerText = group ?? localize('designer.generalGroupName', "General"); componentsToCreate.forEach(component => { if (component.group === group) { - uiComponents.push(this.createComponent(container, component, identifierGetter(component), componentMap, setWidth)); + uiComponents.push(this.createComponent(container, component, parentPath, componentMap, setWidth, isMainView)); } }); }); @@ -551,9 +531,11 @@ export class Designer extends Disposable implements IThemable { private createComponent(container: HTMLElement, componentDefinition: DesignerDataPropertyInfo, - editIdentifier: DesignerEditIdentifier, + parentPath: DesignerEditPath, componentMap: Map, - setWidth: boolean): DesignerUIComponent { + setWidth: boolean, + isMainView: boolean): DesignerUIComponent { + const propertyPath = [...parentPath, componentDefinition.propertyName]; let component: DesignerUIComponent; switch (componentDefinition.componentType) { case 'input': @@ -566,7 +548,7 @@ export class Designer extends Disposable implements IThemable { }); input.onLoseFocus((args) => { if (args.hasChanged) { - this.handleEdit({ type: DesignerEditType.Update, property: editIdentifier, value: args.value }); + this.handleEdit({ type: DesignerEditType.Update, path: propertyPath, value: args.value }); } }); if (setWidth && inputProperties.width !== undefined) { @@ -582,7 +564,7 @@ export class Designer extends Disposable implements IThemable { dropdown.render(dropdownContainer); dropdown.selectElem.style.height = '25px'; dropdown.onDidSelect((e) => { - this.handleEdit({ type: DesignerEditType.Update, property: editIdentifier, value: e.selected }); + this.handleEdit({ type: DesignerEditType.Update, path: propertyPath, value: e.selected }); }); component = dropdown; break; @@ -594,11 +576,14 @@ export class Designer extends Disposable implements IThemable { label: checkboxProperties.title }); checkbox.onChange((newValue) => { - this.handleEdit({ type: DesignerEditType.Update, property: editIdentifier, value: newValue }); + this.handleEdit({ type: DesignerEditType.Update, path: propertyPath, value: newValue }); }); component = checkbox; break; case 'table': + if (!isMainView) { + container.appendChild(DOM.$('.full-row')).appendChild(DOM.$('span.component-label')).innerText = componentDefinition.componentProperties?.title ?? ''; + } const tableProperties = componentDefinition.componentProperties as DesignerTableProperties; if (tableProperties.canAddRows !== false) { const buttonContainer = container.appendChild(DOM.$('.full-row')).appendChild(DOM.$('.add-row-button-container')); @@ -610,7 +595,7 @@ export class Designer extends Disposable implements IThemable { addRowButton.onDidClick(() => { this.handleEdit({ type: DesignerEditType.Add, - property: componentDefinition.propertyName, + path: propertyPath }); }); this.styleComponent(addRowButton); @@ -632,7 +617,9 @@ export class Designer extends Disposable implements IThemable { } else { return undefined; } - } + }, + rowHeight: TableRowHeight, + headerRowHeight: TableHeaderRowHeight }); table.ariaLabel = tableProperties.ariaLabel; const columns = tableProperties.columns.map(propName => { @@ -648,11 +635,7 @@ export class Designer extends Disposable implements IThemable { checkboxColumn.onChange((e) => { this.handleEdit({ type: DesignerEditType.Update, - property: { - parentProperty: componentDefinition.propertyName, - index: e.row, - property: propertyDefinition.propertyName - }, + path: [...propertyPath, e.row, propertyDefinition.propertyName], value: e.value }); }); @@ -662,7 +645,7 @@ export class Designer extends Disposable implements IThemable { return { name: dropdownProperties.title, field: propertyDefinition.propertyName, - editor: this._tableCellEditorFactory.getSelectBoxEditorClass(componentDefinition.propertyName, dropdownProperties.values as string[]), + editor: this._tableCellEditorFactory.getSelectBoxEditorClass(propertyPath, dropdownProperties.values as string[]), width: dropdownProperties.width as number }; default: @@ -670,7 +653,7 @@ export class Designer extends Disposable implements IThemable { return { name: inputProperties.title, field: propertyDefinition.propertyName, - editor: this._tableCellEditorFactory.getTextEditorClass(componentDefinition.propertyName, inputProperties.inputType), + editor: this._tableCellEditorFactory.getTextEditorClass(propertyPath, inputProperties.inputType), width: inputProperties.width as number }; } @@ -685,11 +668,9 @@ export class Designer extends Disposable implements IThemable { isFontIcon: true }); deleteRowColumn.onClick((e) => { - (this._input.viewModel[componentDefinition.propertyName] as DesignerTableProperties).data.splice(e.row, 1); this.handleEdit({ type: DesignerEditType.Remove, - property: componentDefinition.propertyName, - value: e.item + path: [...propertyPath, e.row] }); }); table.registerPlugin(deleteRowColumn); @@ -699,14 +680,15 @@ export class Designer extends Disposable implements IThemable { table.grid.onBeforeEditCell.subscribe((e, data): boolean => { return data.item[data.column.field].enabled !== false; }); - table.grid.onActiveCellChanged.subscribe((e, data) => { - if (data.row !== undefined) { - this.updatePropertiesPane({ - parentProperty: componentDefinition.propertyName, - index: data.row - }); - } - }); + if (isMainView === true) { + table.grid.onActiveCellChanged.subscribe((e, data) => { + if (data.row !== undefined) { + this.updatePropertiesPane([...propertyPath, data.row]); + } else { + this.updatePropertiesPane(DesignerRootObjectPath); + } + }); + } component = table; break; default: diff --git a/src/sql/workbench/browser/designer/designerPropertiesPane.ts b/src/sql/workbench/browser/designer/designerPropertiesPane.ts index 32f081b8db..2d3e54b2f7 100644 --- a/src/sql/workbench/browser/designer/designerPropertiesPane.ts +++ b/src/sql/workbench/browser/designer/designerPropertiesPane.ts @@ -4,18 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { CreateComponentsFunc, DesignerUIComponent, SetComponentValueFunc } from 'sql/workbench/browser/designer/designer'; -import { DesignerViewModel, DesignerDataPropertyInfo } from 'sql/workbench/browser/designer/interfaces'; +import { DesignerViewModel, DesignerDataPropertyInfo, DesignerEditPath } from 'sql/workbench/browser/designer/interfaces'; import * as DOM from 'vs/base/browser/dom'; import { equals } from 'vs/base/common/objects'; import { localize } from 'vs/nls'; -export type PropertiesPaneObjectContext = 'root' | { - parentProperty: string; - index: number; -}; - export interface ObjectInfo { - context: PropertiesPaneObjectContext; + path: DesignerEditPath; type: string; components: DesignerDataPropertyInfo[]; viewModel: DesignerViewModel; @@ -24,7 +19,7 @@ export interface ObjectInfo { export class DesignerPropertiesPane { private _titleElement: HTMLElement; private _contentElement: HTMLElement; - private _currentContext?: PropertiesPaneObjectContext; + private _objectPath: DesignerEditPath; private _componentMap = new Map(); private _groupHeaders: HTMLElement[] = []; @@ -43,8 +38,8 @@ export class DesignerPropertiesPane { return this._componentMap; } - public get context(): PropertiesPaneObjectContext | undefined { - return this._currentContext; + public get objectPath(): DesignerEditPath { + return this._objectPath; } public clear(): void { @@ -54,20 +49,14 @@ export class DesignerPropertiesPane { this._componentMap.clear(); this._groupHeaders = []; DOM.clearNode(this._contentElement); - this._currentContext = undefined; + this._objectPath = undefined; } public show(item: ObjectInfo): void { - if (!equals(item.context, this._currentContext)) { + if (!equals(item.path, this._objectPath)) { this.clear(); - this._currentContext = item.context; - this._createComponents(this._contentElement, item.components, (property) => { - return this._currentContext === 'root' ? property.propertyName : { - parentProperty: this._currentContext.parentProperty, - index: this._currentContext.index, - property: property.propertyName - }; - }); + this._objectPath = item.path; + this._createComponents(this._contentElement, item.components, this.objectPath); } this._titleElement.innerText = localize({ key: 'tableDesigner.propertiesPaneTitleWithContext', diff --git a/src/sql/workbench/browser/designer/designerTabPanelView.ts b/src/sql/workbench/browser/designer/designerTabPanelView.ts index 1e4a153689..9934afbf94 100644 --- a/src/sql/workbench/browser/designer/designerTabPanelView.ts +++ b/src/sql/workbench/browser/designer/designerTabPanelView.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { DesignerTab } from 'sql/workbench/browser/designer/interfaces'; +import { DesignerRootObjectPath, DesignerTab } from 'sql/workbench/browser/designer/interfaces'; import { IPanelView } from 'sql/base/browser/ui/panel/panel'; import { Table } from 'sql/base/browser/ui/table/table'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -20,7 +20,7 @@ export class DesignerTabPanelView extends Disposable implements IPanelView { constructor(private readonly _tab: DesignerTab, private _createComponents: CreateComponentsFunc) { super(); this._componentsContainer = DOM.$('.components-grid'); - const uiComponents = this._createComponents(this._componentsContainer, this._tab.components, component => component.propertyName); + const uiComponents = this._createComponents(this._componentsContainer, this._tab.components, DesignerRootObjectPath); uiComponents.forEach(component => { if (component instanceof Table) { this._tables.push(component); diff --git a/src/sql/workbench/browser/designer/interfaces.ts b/src/sql/workbench/browser/designer/interfaces.ts index 095177f1f2..279d0555cd 100644 --- a/src/sql/workbench/browser/designer/interfaces.ts +++ b/src/sql/workbench/browser/designer/interfaces.ts @@ -113,6 +113,7 @@ export interface DesignerDataPropertyInfo { propertyName: string; description?: string; componentType: DesignerComponentTypeName; + showInPropertiesView?: boolean; group?: string; componentProperties?: InputBoxProperties | CheckBoxProperties | DropDownProperties | DesignerTableProperties; } @@ -193,15 +194,16 @@ export enum DesignerEditType { export interface DesignerEdit { type: DesignerEditType; - property: DesignerEditIdentifier; + path: DesignerEditPath; value?: any; } -export type DesignerEditIdentifier = string | { parentProperty: string, index: number, property: string }; +export type DesignerEditPath = (string | number)[]; +export const DesignerRootObjectPath: DesignerEditPath = []; export interface DesignerEditResult { isValid: boolean; - errors?: { message: string, property?: DesignerEditIdentifier }[]; + errors?: { message: string, property?: DesignerEditPath }[]; } export interface DesignerTextEditor { diff --git a/src/sql/workbench/contrib/tableDesigner/browser/tableDesignerEditor.ts b/src/sql/workbench/contrib/tableDesigner/browser/tableDesignerEditor.ts index 20c375f7ec..36ebd1bc83 100644 --- a/src/sql/workbench/contrib/tableDesigner/browser/tableDesignerEditor.ts +++ b/src/sql/workbench/contrib/tableDesigner/browser/tableDesignerEditor.ts @@ -10,7 +10,6 @@ import { TableDesignerInput } from 'sql/workbench/browser/editor/tableDesigner/t import * as DOM from 'vs/base/browser/dom'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IEditorOptions } from 'vs/platform/editor/common/editor'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -32,8 +31,7 @@ export class TableDesignerEditor extends EditorPane { @ITelemetryService telemetryService: ITelemetryService, @IWorkbenchThemeService themeService: IWorkbenchThemeService, @IStorageService storageService: IStorageService, - @IContextViewService private _contextViewService: IContextViewService, - @IInstantiationService private _instantiationService: IInstantiationService + @IInstantiationService private _instantiationService: IInstantiationService, ) { super(TableDesignerEditor.ID, telemetryService, themeService, storageService); } @@ -60,7 +58,7 @@ export class TableDesignerEditor extends EditorPane { this._saveChangesAction.enabled = false; actionbar.push(this._saveChangesAction, { icon: true, label: false }); - this._designer = new Designer(designerContainer, this._instantiationService, this._contextViewService); + this._designer = this._instantiationService.createInstance(Designer, designerContainer); this._register(attachDesignerStyler(this._designer, this.themeService)); this._register(registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => { const border = theme.getColor(DesignerPaneSeparator); diff --git a/src/sql/workbench/services/tableDesigner/browser/tableDesignerComponentInput.ts b/src/sql/workbench/services/tableDesigner/browser/tableDesignerComponentInput.ts index da674f7c6e..a1d757f2eb 100644 --- a/src/sql/workbench/services/tableDesigner/browser/tableDesignerComponentInput.ts +++ b/src/sql/workbench/services/tableDesigner/browser/tableDesignerComponentInput.ts @@ -251,6 +251,7 @@ export class TableDesignerComponentInput implements DesignerComponentInput { { componentType: 'table', propertyName: designers.TableProperty.Columns, + showInPropertiesView: false, componentProperties: { ariaLabel: localize('tableDesigner.columnsTabTitle', "Columns"), columns: columnsTableProperties,