diff --git a/extensions/mssql/config.json b/extensions/mssql/config.json index 8ed7d8d26f..ebd527c331 100644 --- a/extensions/mssql/config.json +++ b/extensions/mssql/config.json @@ -1,6 +1,6 @@ { "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", - "version": "3.0.0-release.182", + "version": "3.0.0-release.184", "downloadFileNames": { "Windows_86": "win-x86-net6.0.zip", "Windows_64": "win-x64-net6.0.zip", diff --git a/src/sql/azdata.proposed.d.ts b/src/sql/azdata.proposed.d.ts index 375f36c0b9..47d6baef08 100644 --- a/src/sql/azdata.proposed.d.ts +++ b/src/sql/azdata.proposed.d.ts @@ -1134,6 +1134,7 @@ declare module 'azdata' { Script = 'script', ForeignKeys = 'foreignKeys', CheckConstraints = 'checkConstraints', + Indexes = 'indexes' } /** * Name of the common table column properties. @@ -1179,6 +1180,22 @@ declare module 'azdata' { Expression = 'expression' } + /** + * Name of the common index properties. + * Extensions can use the name to access the designer view model. + */ + export enum TableIndexProperty { + Name = 'name', + Columns = 'columns' + } + + /** + * Name of the common properties of table index column specification. + */ + export enum TableIndexColumnSpecificationProperty { + Column = 'column' + } + /** * The table designer view definition. */ @@ -1209,6 +1226,19 @@ declare module 'azdata' { * Default columns to display values are: Name, Expression. */ checkConstraintTableOptions?: TableDesignerBuiltInTableViewOptions; + /** + * Indexes table options. + * Common index properties are handled by Azure Data Studio. see {@link TableIndexProperty} + * Default columns to display values are: Name. + */ + indexTableOptions?: TableDesignerBuiltInTableViewOptions; + + /** + * Index column specification table options. + * Common index properties are handled by Azure Data Studio. see {@link TableIndexColumnSpecificationProperty} + * Default columns to display values are: Column. + */ + indexColumnSpecificationTableOptions?: TableDesignerBuiltInTableViewOptions; } export interface TableDesignerBuiltInTableViewOptions { diff --git a/src/sql/workbench/api/common/sqlExtHost.api.impl.ts b/src/sql/workbench/api/common/sqlExtHost.api.impl.ts index af645132d3..e955645858 100644 --- a/src/sql/workbench/api/common/sqlExtHost.api.impl.ts +++ b/src/sql/workbench/api/common/sqlExtHost.api.impl.ts @@ -575,6 +575,8 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp TableForeignKeyProperty: sqlExtHostTypes.designers.TableForeignKeyProperty, ForeignKeyColumnMappingProperty: sqlExtHostTypes.designers.ForeignKeyColumnMappingProperty, TableCheckConstraintProperty: sqlExtHostTypes.designers.TableCheckConstraintProperty, + TableIndexProperty: sqlExtHostTypes.designers.TableIndexProperty, + TableIndexColumnSpecificationProperty: sqlExtHostTypes.designers.TableIndexColumnSpecificationProperty, DesignerEditType: sqlExtHostTypes.designers.DesignerEditType, openTableDesigner(providerId, tableInfo: azdata.designers.TableInfo): Promise { return extHostDataProvider.$openTableDesigner(providerId, tableInfo); diff --git a/src/sql/workbench/api/common/sqlExtHostTypes.ts b/src/sql/workbench/api/common/sqlExtHostTypes.ts index 0c4b97c369..b46de77aaf 100644 --- a/src/sql/workbench/api/common/sqlExtHostTypes.ts +++ b/src/sql/workbench/api/common/sqlExtHostTypes.ts @@ -953,6 +953,7 @@ export namespace designers { Script = 'script', ForeignKeys = 'foreignKeys', CheckConstraints = 'checkConstraints', + Indexes = 'indexes' } export enum TableColumnProperty { @@ -984,6 +985,15 @@ export namespace designers { Expression = 'expression' } + export enum TableIndexProperty { + Name = 'name', + Columns = 'columns' + } + + export enum TableIndexColumnSpecificationProperty { + Column = 'column' + } + export enum DesignerEditType { Add = 0, Remove = 1, diff --git a/src/sql/workbench/browser/designer/designer.ts b/src/sql/workbench/browser/designer/designer.ts index a6b8dada17..f5e0f132b6 100644 --- a/src/sql/workbench/browser/designer/designer.ts +++ b/src/sql/workbench/browser/designer/designer.ts @@ -639,7 +639,7 @@ export class Designer extends Disposable implements IThemable { autoEdit: true, dataItemColumnValueExtractor: (data: any, column: Slick.Column): string => { if (column.field) { - return data[column.field].value; + return data[column.field]?.value; } else { return undefined; } diff --git a/src/sql/workbench/browser/editor/tableDesigner/tableDesignerInput.ts b/src/sql/workbench/browser/editor/tableDesigner/tableDesignerInput.ts index 4d424f34ac..b636b7ef1b 100644 --- a/src/sql/workbench/browser/editor/tableDesigner/tableDesignerInput.ts +++ b/src/sql/workbench/browser/editor/tableDesigner/tableDesignerInput.ts @@ -14,6 +14,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Schemas } from 'sql/base/common/schemas'; +import { INotificationService } from 'vs/platform/notification/common/notification'; const NewTable: string = localize('tableDesigner.newTable', "New Table"); @@ -27,7 +28,8 @@ export class TableDesignerInput extends EditorInput { private _provider: TableDesignerProvider, private _tableInfo: azdata.designers.TableInfo, @IInstantiationService private readonly _instantiationService: IInstantiationService, - @IEditorService editorService: IEditorService) { + @IEditorService editorService: IEditorService, + @INotificationService private readonly _notificationService: INotificationService) { super(); this._designerComponentInput = this._instantiationService.createInstance(TableDesignerComponentInput, this._provider, this._tableInfo); this._register(this._designerComponentInput.onStateChange((e) => { @@ -81,7 +83,11 @@ export class TableDesignerInput extends EditorInput { } override async save(group: GroupIdentifier, options?: ISaveOptions): Promise { - await this._designerComponentInput.openPublishDialog(); + if (this._designerComponentInput.pendingAction) { + this._notificationService.warn(localize('tableDesigner.OperationInProgressWarning', "The operation cannot be performed while another operation is in progress.")); + } else { + await this._designerComponentInput.openPublishDialog(); + } return this; } diff --git a/src/sql/workbench/services/tableDesigner/browser/tableDesignerComponentInput.ts b/src/sql/workbench/services/tableDesigner/browser/tableDesignerComponentInput.ts index 1a8a431065..25169fbc8c 100644 --- a/src/sql/workbench/services/tableDesigner/browser/tableDesignerComponentInput.ts +++ b/src/sql/workbench/services/tableDesigner/browser/tableDesignerComponentInput.ts @@ -212,6 +212,10 @@ export class TableDesignerComponentInput implements DesignerComponentInput { tabs.push(this.getCheckConstraintsTab(designerInfo.view.checkConstraintTableOptions)); } + if (designerInfo.view.indexTableOptions?.showTable) { + tabs.push(this.getIndexesTab(designerInfo.view.indexTableOptions, designerInfo.view.indexColumnSpecificationTableOptions)); + } + if (designerInfo.view.additionalTabs) { tabs.push(...designerInfo.view.additionalTabs); } @@ -331,11 +335,7 @@ export class TableDesignerComponentInput implements DesignerComponentInput { } ]; - if (options.additionalProperties) { - columnProperties.push(...options.additionalProperties); - } - - const displayProperties = options.propertiesToDisplay?.length > 0 ? options.propertiesToDisplay : [ + const displayProperties = this.getTableDisplayProperties(options, [ designers.TableColumnProperty.Name, designers.TableColumnProperty.Type, designers.TableColumnProperty.Length, @@ -344,7 +344,7 @@ export class TableDesignerComponentInput implements DesignerComponentInput { designers.TableColumnProperty.IsPrimaryKey, designers.TableColumnProperty.AllowNulls, designers.TableColumnProperty.DefaultValue, - ]; + ]); return { title: localize('tableDesigner.columnsTabTitle', "Columns"), @@ -356,7 +356,7 @@ export class TableDesignerComponentInput implements DesignerComponentInput { componentProperties: { ariaLabel: localize('tableDesigner.columnsTabTitle', "Columns"), columns: displayProperties, - itemProperties: columnProperties, + itemProperties: this.addAdditionalTableProperties(options, columnProperties), objectTypeDisplayName: localize('tableDesigner.columnTypeName', "Column"), canAddRows: options.canAddRows, canRemoveRows: options.canRemoveRows @@ -437,16 +437,7 @@ export class TableDesignerComponentInput implements DesignerComponentInput { canAddRows: options.canAddRows, canRemoveRows: options.canRemoveRows } - }, - ]; - - if (options.additionalProperties) { - foreignKeyProperties.push(...options.additionalProperties); - } - - const displayProperties = options.propertiesToDisplay?.length > 0 ? options.propertiesToDisplay : [ - designers.TableForeignKeyProperty.Name, - designers.TableForeignKeyProperty.PrimaryKeyTable + } ]; return { @@ -458,8 +449,8 @@ export class TableDesignerComponentInput implements DesignerComponentInput { showInPropertiesView: false, componentProperties: { ariaLabel: localize('tableDesigner.foreignKeysTabTitle', "Foreign Keys"), - columns: displayProperties, - itemProperties: foreignKeyProperties, + columns: this.getTableDisplayProperties(options, [designers.TableForeignKeyProperty.Name, designers.TableForeignKeyProperty.PrimaryKeyTable]), + itemProperties: this.addAdditionalTableProperties(options, foreignKeyProperties), objectTypeDisplayName: localize('tableDesigner.ForeignKeyTypeName', "Foreign Key"), canAddRows: options.canAddRows, canRemoveRows: options.canRemoveRows @@ -490,12 +481,6 @@ export class TableDesignerComponentInput implements DesignerComponentInput { } ]; - if (options.additionalProperties) { - checkConstraintProperties.push(...options.additionalProperties); - } - - const displayProperties = options.propertiesToDisplay?.length > 0 ? options.propertiesToDisplay : [designers.TableCheckConstraintProperty.Name, designers.TableCheckConstraintProperty.Expression]; - return { title: localize('tableDesigner.checkConstraintsTabTitle', "Check Constraints"), components: [ @@ -505,8 +490,8 @@ export class TableDesignerComponentInput implements DesignerComponentInput { showInPropertiesView: false, componentProperties: { ariaLabel: localize('tableDesigner.checkConstraintsTabTitle', "Check Constraints"), - columns: displayProperties, - itemProperties: checkConstraintProperties, + columns: this.getTableDisplayProperties(options, [designers.TableCheckConstraintProperty.Name, designers.TableCheckConstraintProperty.Expression]), + itemProperties: this.addAdditionalTableProperties(options, checkConstraintProperties), objectTypeDisplayName: localize('tableDesigner.checkConstraintTypeName', "Check Constraint"), canAddRows: options.canAddRows, canRemoveRows: options.canRemoveRows @@ -515,6 +500,74 @@ export class TableDesignerComponentInput implements DesignerComponentInput { ] }; } + + private getIndexesTab(options: azdata.designers.TableDesignerBuiltInTableViewOptions, columnSpecTableOptions: azdata.designers.TableDesignerBuiltInTableViewOptions): DesignerTab { + const columnSpecProperties: DesignerDataPropertyInfo[] = [ + { + componentType: 'dropdown', + propertyName: designers.TableIndexColumnSpecificationProperty.Column, + description: localize('designer.index.column.description.name', "The name of the column."), + componentProperties: { + title: localize('tableDesigner.index.column.name', "Column"), + width: 100 + } + }]; + const indexProperties: DesignerDataPropertyInfo[] = [ + { + componentType: 'input', + propertyName: designers.TableIndexProperty.Name, + description: localize('designer.index.description.name', "The name of the index."), + componentProperties: { + title: localize('tableDesigner.indexName', "Name"), + width: 200 + } + }, { + componentType: 'table', + propertyName: designers.TableIndexProperty.Columns, + description: localize('designer.index.description.columns', "The columns of the index."), + group: localize('tableDesigner.indexColumns', "Columns"), + componentProperties: { + ariaLabel: localize('tableDesigner.indexColumns', "Columns"), + columns: this.getTableDisplayProperties(columnSpecTableOptions, [designers.TableIndexColumnSpecificationProperty.Column]), + itemProperties: this.addAdditionalTableProperties(columnSpecTableOptions, columnSpecProperties), + objectTypeDisplayName: '', + canAddRows: columnSpecTableOptions.canAddRows, + canRemoveRows: columnSpecTableOptions.canRemoveRows + } + } + ]; + + return { + title: localize('tableDesigner.indexesTabTitle', "Indexes"), + components: [ + { + componentType: 'table', + propertyName: designers.TableProperty.Indexes, + showInPropertiesView: false, + componentProperties: { + ariaLabel: localize('tableDesigner.indexesTabTitle', "Indexes"), + columns: this.getTableDisplayProperties(options, [designers.TableIndexProperty.Name]), + itemProperties: this.addAdditionalTableProperties(options, indexProperties), + objectTypeDisplayName: localize('tableDesigner.IndexTypeName', "Index"), + canAddRows: options.canAddRows, + canRemoveRows: options.canRemoveRows + } + } + ] + }; + } + + private getTableDisplayProperties(options: azdata.designers.TableDesignerBuiltInTableViewOptions, defaultProperties: string[]): string[] { + return options.propertiesToDisplay?.length > 0 ? options.propertiesToDisplay : defaultProperties; + } + + private addAdditionalTableProperties(options: azdata.designers.TableDesignerBuiltInTableViewOptions, properties: DesignerDataPropertyInfo[]): DesignerDataPropertyInfo[] { + if (options.additionalProperties) { + properties.push(...options.additionalProperties); + } + return properties; + } + private setDefaultData(): void { const properties = Object.keys(this._viewModel); this.setDefaultInputData(properties, designers.TableProperty.Name);