diff --git a/extensions/mssql/src/contracts.ts b/extensions/mssql/src/contracts.ts index 5df83df002..12afcee081 100644 --- a/extensions/mssql/src/contracts.ts +++ b/extensions/mssql/src/contracts.ts @@ -1050,4 +1050,7 @@ export namespace SaveTableDesignerChangesRequest { export const type = new RequestType('tabledesigner/savechanges'); } +export namespace DisposeTableDesignerRequest { + export const type = new RequestType('tabledesigner/dispose'); +} // ------------------------------- < Table Designer > ------------------------------------ diff --git a/extensions/mssql/src/features.ts b/extensions/mssql/src/features.ts index 67093936a8..812df28c23 100644 --- a/extensions/mssql/src/features.ts +++ b/extensions/mssql/src/features.ts @@ -1146,11 +1146,22 @@ export class TableDesignerFeature extends SqlOpsFeature { } }; + const disposeTableDesigner = (tableInfo: azdata.designers.TableInfo): Thenable => { + try { + return client.sendRequest(contracts.DisposeTableDesignerRequest.type, tableInfo); + } + catch (e) { + client.logFailedRequest(contracts.DisposeTableDesignerRequest.type, e); + return Promise.reject(e); + } + }; + return azdata.dataprotocol.registerTableDesignerProvider({ providerId: client.providerId, getTableDesignerInfo, processTableEdit, - saveTable + saveTable, + disposeTableDesigner }); } } diff --git a/extensions/mssql/src/tableDesigner/tableDesigner.ts b/extensions/mssql/src/tableDesigner/tableDesigner.ts index ab33daee98..2b1dbbb09c 100644 --- a/extensions/mssql/src/tableDesigner/tableDesigner.ts +++ b/extensions/mssql/src/tableDesigner/tableDesigner.ts @@ -7,15 +7,17 @@ import { AppContext } from '../appContext'; import * as azdata from 'azdata'; import * as vscode from 'vscode'; import { sqlProviderName } from '../constants'; +import { generateUuid } from 'vscode-languageclient/lib/utils/uuid'; export function registerTableDesignerCommands(appContext: AppContext) { appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.newTable', async (context: azdata.ObjectExplorerContext) => { - const connectionUri = await azdata.connection.getUriForConnection(context.connectionProfile.id); + const connectionString = await azdata.connection.getConnectionString(context.connectionProfile.id, true); await azdata.designers.openTableDesigner(sqlProviderName, { server: context.connectionProfile.serverName, database: context.connectionProfile.databaseName, isNewTable: true, - connectionUri: connectionUri + id: generateUuid(), + connectionString: connectionString }); })); @@ -24,6 +26,7 @@ export function registerTableDesignerCommands(appContext: AppContext) { const database = context.connectionProfile.databaseName; const schema = context.nodeInfo.metadata.schema; const name = context.nodeInfo.metadata.name; + const connectionString = await azdata.connection.getConnectionString(context.connectionProfile.id, true); const connectionUri = await azdata.connection.getUriForConnection(context.connectionProfile.id); await azdata.designers.openTableDesigner(sqlProviderName, { server: server, @@ -31,9 +34,8 @@ export function registerTableDesignerCommands(appContext: AppContext) { isNewTable: false, name: name, schema: schema, - id: `${server}|${database}|${schema}|${name}`, - connectionUri: connectionUri + id: `${connectionUri}|${database}|${schema}|${name}`, + connectionString: connectionString }); })); - } diff --git a/src/sql/azdata.proposed.d.ts b/src/sql/azdata.proposed.d.ts index 341a7405c0..2d14e4f6dd 100644 --- a/src/sql/azdata.proposed.d.ts +++ b/src/sql/azdata.proposed.d.ts @@ -1028,6 +1028,12 @@ declare module 'azdata' { * @param viewModel the object contains the state of the table designer */ saveTable(table: TableInfo, viewModel: DesignerViewModel): Thenable; + + /** + * Notify the provider that the table designer has been closed. + * @param table the table information + */ + disposeTableDesigner(table: TableInfo): Thenable; } /** @@ -1055,9 +1061,9 @@ declare module 'azdata' { */ isNewTable: boolean; /** - * If this is not a new table, the id will be set to uniquely identify a table. + * Unique identifier of the table. Will be used to decide whether a designer is already opened for the table. */ - id?: string; + id: string; /** * Extension can store additional information that the provider needs to uniquely identify a table. */ diff --git a/src/sql/workbench/api/browser/mainThreadDataProtocol.ts b/src/sql/workbench/api/browser/mainThreadDataProtocol.ts index 812dc9a028..5c8282c41d 100644 --- a/src/sql/workbench/api/browser/mainThreadDataProtocol.ts +++ b/src/sql/workbench/api/browser/mainThreadDataProtocol.ts @@ -521,6 +521,9 @@ export class MainThreadDataProtocol extends Disposable implements MainThreadData }, saveTable(tableInfo: azdata.designers.TableInfo, data: azdata.designers.DesignerViewModel): Thenable { return self._proxy.$saveTable(handle, tableInfo, data); + }, + disposeTableDesigner(tableInfo: azdata.designers.TableInfo): Thenable { + return self._proxy.$disposeTableDesigner(handle, tableInfo); } }); diff --git a/src/sql/workbench/api/common/extHostDataProtocol.ts b/src/sql/workbench/api/common/extHostDataProtocol.ts index 8891a878fa..69d8660659 100644 --- a/src/sql/workbench/api/common/extHostDataProtocol.ts +++ b/src/sql/workbench/api/common/extHostDataProtocol.ts @@ -892,16 +892,20 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape { } // Table Designer - public override $getTableDesignerInfo(handle, table: azdata.designers.TableInfo): Thenable { + public override $getTableDesignerInfo(handle: number, table: azdata.designers.TableInfo): Thenable { return this._resolveProvider(handle).getTableDesignerInfo(table); } - public override $processTableDesignerEdit(handle, table: azdata.designers.TableInfo, data: azdata.designers.DesignerViewModel, edit: azdata.designers.DesignerEdit): Thenable { - return this._resolveProvider(handle).processTableEdit(table, data, edit); + public override $processTableDesignerEdit(handle: number, table: azdata.designers.TableInfo, viewModel: azdata.designers.DesignerViewModel, edit: azdata.designers.DesignerEdit): Thenable { + return this._resolveProvider(handle).processTableEdit(table, viewModel, edit); } - public override $saveTable(handle, table: azdata.designers.TableInfo, data: azdata.designers.DesignerViewModel): Thenable { - return this._resolveProvider(handle).saveTable(table, data); + public override $saveTable(handle: number, table: azdata.designers.TableInfo, viewModel: azdata.designers.DesignerViewModel): Thenable { + return this._resolveProvider(handle).saveTable(table, viewModel); + } + + public override $disposeTableDesigner(handle: number, table: azdata.designers.TableInfo): Thenable { + return this._resolveProvider(handle).disposeTableDesigner(table); } public override $openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo): Promise { diff --git a/src/sql/workbench/api/common/sqlExtHost.protocol.ts b/src/sql/workbench/api/common/sqlExtHost.protocol.ts index a3b24e1d77..e56840fe71 100644 --- a/src/sql/workbench/api/common/sqlExtHost.protocol.ts +++ b/src/sql/workbench/api/common/sqlExtHost.protocol.ts @@ -530,17 +530,22 @@ export abstract class ExtHostDataProtocolShape { /** * Gets the table designer info for the specified table */ - $getTableDesignerInfo(handle, table: azdata.designers.TableInfo): Thenable { throw ni(); } + $getTableDesignerInfo(handle: number, table: azdata.designers.TableInfo): Thenable { throw ni(); } /** * Process the table edit. */ - $processTableDesignerEdit(handle, table: azdata.designers.TableInfo, data: azdata.designers.DesignerViewModel, edit: azdata.designers.DesignerEdit): Thenable { throw ni(); } + $processTableDesignerEdit(handle: number, table: azdata.designers.TableInfo, data: azdata.designers.DesignerViewModel, edit: azdata.designers.DesignerEdit): Thenable { throw ni(); } /** * Process the table edit. */ - $saveTable(handle, table: azdata.designers.TableInfo, data: azdata.designers.DesignerViewModel): Thenable { throw ni(); } + $saveTable(handle: number, table: azdata.designers.TableInfo, data: azdata.designers.DesignerViewModel): Thenable { throw ni(); } + + /** + * Dispose the table designer. + */ + $disposeTableDesigner(handle: number, table: azdata.designers.TableInfo): Thenable { throw ni(); } /** * Open a new instance of table designer. diff --git a/src/sql/workbench/browser/editor/tableDesigner/tableDesignerInput.ts b/src/sql/workbench/browser/editor/tableDesigner/tableDesignerInput.ts index ca7f24df91..3bc4c83105 100644 --- a/src/sql/workbench/browser/editor/tableDesigner/tableDesignerInput.ts +++ b/src/sql/workbench/browser/editor/tableDesigner/tableDesignerInput.ts @@ -12,6 +12,7 @@ import * as azdata from 'azdata'; import { GroupIdentifier, IEditorInput, IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { onUnexpectedError } from 'vs/base/common/errors'; const NewTable: string = localize('tableDesigner.newTable', "New Table"); @@ -78,12 +79,13 @@ export class TableDesignerInput extends EditorInput { } override matches(otherInput: any): boolean { - // For existing tables, the table designer provider will give us unique id, we can use it to do the match. - // For new tables, we can do the match using their names. return otherInput instanceof TableDesignerInput && this._provider.providerId === otherInput._provider.providerId - && this._tableInfo.isNewTable === otherInput._tableInfo.isNewTable - && (!this._tableInfo.isNewTable || this.getName() === otherInput.getName()) - && (this._tableInfo.isNewTable || this._tableInfo.id === otherInput._tableInfo.id); + && this._tableInfo.id === otherInput._tableInfo.id; + } + + override dispose(): void { + super.dispose(); + this._provider.disposeTableDesigner(this._tableInfo).then(undefined, err => onUnexpectedError(err)); } }