diff --git a/extensions/dacpac/src/wizard/dataTierApplicationWizard.ts b/extensions/dacpac/src/wizard/dataTierApplicationWizard.ts index c341e8b96d..e54546aed0 100644 --- a/extensions/dacpac/src/wizard/dataTierApplicationWizard.ts +++ b/extensions/dacpac/src/wizard/dataTierApplicationWizard.ts @@ -125,7 +125,16 @@ export class DataTierApplicationWizard { this.setPages(); this.configureButtons(); - this.wizard.open(); + // the wizard was started from the context menu of a database or server if the connectionProfile is not undefined + // Otherwise it was launched from the command palette + let launchedFrom: string; + if (profile) { + launchedFrom = profile.databaseName ? 'database context menu' : 'server context menu'; + } else { + launchedFrom = 'command palette'; + } + + this.wizard.open(launchedFrom); return true; } diff --git a/src/sql/azdata.proposed.d.ts b/src/sql/azdata.proposed.d.ts index f99e13973c..02b8ecd034 100644 --- a/src/sql/azdata.proposed.d.ts +++ b/src/sql/azdata.proposed.d.ts @@ -584,6 +584,12 @@ declare module 'azdata' { * Width of the wizard */ width?: DialogWidth; + + /** + * Open the wizard. Does nothing if the wizard is already open. + * @param source Where the wizard was opened from for telemetry (ex: command palette, context menu) + */ + open(source?: string): Thenable; } export interface WizardPage extends ModelViewPanel { diff --git a/src/sql/workbench/api/browser/mainThreadModelViewDialog.ts b/src/sql/workbench/api/browser/mainThreadModelViewDialog.ts index c870fbfac2..034853fc1d 100644 --- a/src/sql/workbench/api/browser/mainThreadModelViewDialog.ts +++ b/src/sql/workbench/api/browser/mainThreadModelViewDialog.ts @@ -256,11 +256,11 @@ export class MainThreadModelViewDialog implements MainThreadModelViewDialogShape return modal.showPage(pageIndex); } - public $openWizard(handle: number): Thenable { + public $openWizard(handle: number, source?: string): Thenable { let wizard = this.getWizard(handle); const options = assign({}, DefaultWizardOptions); options.width = wizard.width; - this._dialogService.showWizard(wizard, options); + this._dialogService.showWizard(wizard, options, source); return Promise.resolve(); } diff --git a/src/sql/workbench/api/common/extHostModelViewDialog.ts b/src/sql/workbench/api/common/extHostModelViewDialog.ts index c407334e0c..db10b9679d 100644 --- a/src/sql/workbench/api/common/extHostModelViewDialog.ts +++ b/src/sql/workbench/api/common/extHostModelViewDialog.ts @@ -502,8 +502,8 @@ class WizardImpl implements azdata.window.Wizard { return this._extHostModelViewDialog.setWizardPage(this, index); } - public open(): Thenable { - return this._extHostModelViewDialog.openWizard(this); + public open(source?: string): Thenable { + return this._extHostModelViewDialog.openWizard(this, source); } public close(): Thenable { @@ -943,10 +943,10 @@ export class ExtHostModelViewDialog implements ExtHostModelViewDialogShape { return this._proxy.$setWizardPage(this.getHandle(wizard), pageIndex); } - public openWizard(wizard: azdata.window.Wizard): Thenable { + public openWizard(wizard: azdata.window.Wizard, source?: string): Thenable { let handle = this.getHandle(wizard); this.updateWizard(wizard); - return this._proxy.$openWizard(handle); + return this._proxy.$openWizard(handle, source); } public closeWizard(wizard: azdata.window.Wizard): Thenable { diff --git a/src/sql/workbench/api/common/sqlExtHost.protocol.ts b/src/sql/workbench/api/common/sqlExtHost.protocol.ts index 412febb3cf..00bd4f1920 100644 --- a/src/sql/workbench/api/common/sqlExtHost.protocol.ts +++ b/src/sql/workbench/api/common/sqlExtHost.protocol.ts @@ -826,7 +826,7 @@ export interface MainThreadModelViewDialogShape extends IDisposable { $setDialogDetails(handle: number, details: IModelViewDialogDetails): Thenable; $setTabDetails(handle: number, details: IModelViewTabDetails): Thenable; $setButtonDetails(handle: number, details: IModelViewButtonDetails): Thenable; - $openWizard(handle: number): Thenable; + $openWizard(handle: number, source?: string): Thenable; $closeWizard(handle: number): Thenable; $setWizardPageDetails(handle: number, details: IModelViewWizardPageDetails): Thenable; $setWizardDetails(handle: number, details: IModelViewWizardDetails): Thenable; diff --git a/src/sql/workbench/browser/modal/modal.ts b/src/sql/workbench/browser/modal/modal.ts index 3efc97a79c..e7526beee9 100644 --- a/src/sql/workbench/browser/modal/modal.ts +++ b/src/sql/workbench/browser/modal/modal.ts @@ -465,8 +465,9 @@ export abstract class Modal extends Disposable implements IThemable { /** * Shows the modal and attaches key listeners + * @param source Where the modal was opened from for telemetry (ex: command palette, context menu) */ - protected show() { + protected show(source?: string) { if (this._modalOptions.dialogStyle === 'callout') { this.positionCalloutDialog(); } @@ -496,7 +497,7 @@ export abstract class Modal extends Disposable implements IThemable { })); this.layout(DOM.getTotalHeight(this._modalBodySection!)); - this._telemetryService.createActionEvent(TelemetryKeys.TelemetryView.Shell, TelemetryKeys.TelemetryAction.ModalDialogOpened) + this._telemetryService.createActionEvent(TelemetryKeys.TelemetryView.Shell, TelemetryKeys.TelemetryAction.ModalDialogOpened, undefined, source) .withAdditionalProperties({ name: this._name }) .send(); } diff --git a/src/sql/workbench/services/dialog/browser/customDialogService.ts b/src/sql/workbench/services/dialog/browser/customDialogService.ts index 2a1a1219ce..817462e0ad 100644 --- a/src/sql/workbench/services/dialog/browser/customDialogService.ts +++ b/src/sql/workbench/services/dialog/browser/customDialogService.ts @@ -32,11 +32,11 @@ export class CustomDialogService { dialogModal.open(); } - public showWizard(wizard: Wizard, options?: IModalOptions): void { + public showWizard(wizard: Wizard, options?: IModalOptions, source?: string): void { let wizardModal = this._instantiationService.createInstance(WizardModal, wizard, options || DefaultWizardOptions); this._wizardModals.set(wizard, wizardModal); wizardModal.render(); - wizardModal.open(); + wizardModal.open(source); } public closeDialog(dialog: Dialog): void { diff --git a/src/sql/workbench/services/dialog/browser/wizardModal.ts b/src/sql/workbench/services/dialog/browser/wizardModal.ts index 7038af0591..8a3bf0ab7f 100644 --- a/src/sql/workbench/services/dialog/browser/wizardModal.ts +++ b/src/sql/workbench/services/dialog/browser/wizardModal.ts @@ -261,9 +261,13 @@ export class WizardModal extends Modal { () => undefined); } - public open(): void { + /** + * Opens the dialog to the first page + * @param source Where the wizard was opened from for telemetry (ex: command palette, context menu) + */ + public open(source?: string): void { this.showPage(0, false, true).then(() => { - this.show(); + this.show(source); }).catch(err => onUnexpectedError(err)); } diff --git a/src/sql/workbench/test/electron-browser/api/extHostModelViewDialog.test.ts b/src/sql/workbench/test/electron-browser/api/extHostModelViewDialog.test.ts index 06250cb687..2dc9011e63 100644 --- a/src/sql/workbench/test/electron-browser/api/extHostModelViewDialog.test.ts +++ b/src/sql/workbench/test/electron-browser/api/extHostModelViewDialog.test.ts @@ -141,13 +141,14 @@ suite('ExtHostModelViewDialog Tests', () => { }); test('Opening a wizard updates its pages and buttons on the main thread', () => { - mockProxy.setup(x => x.$openWizard(It.isAny())); + mockProxy.setup(x => x.$openWizard(It.isAny(), It.isAny())); mockProxy.setup(x => x.$setWizardDetails(It.isAny(), It.isAny())); mockProxy.setup(x => x.$setWizardPageDetails(It.isAny(), It.isAny())); mockProxy.setup(x => x.$setButtonDetails(It.isAny(), It.isAny())); // Create a wizard with 2 pages and 2 custom buttons let wizardTitle = 'wizard_title'; + let source = 'command palette'; let wizard = extHostModelViewDialog.createWizard(wizardTitle); let page1Title = 'page_1'; let page1 = extHostModelViewDialog.createWizardPage(page1Title); @@ -162,7 +163,7 @@ suite('ExtHostModelViewDialog Tests', () => { wizard.customButtons = [button1, button2]; // Open the wizard and verify that the correct main thread methods were called - extHostModelViewDialog.openWizard(wizard); + extHostModelViewDialog.openWizard(wizard, source); mockProxy.verify(x => x.$setButtonDetails(It.isAny(), It.is(details => { return details.enabled === false && details.label === button1Label; })), Times.atLeastOnce()); @@ -179,7 +180,7 @@ suite('ExtHostModelViewDialog Tests', () => { return details.title === wizardTitle && details.pages.length === 2 && details.customButtons.length === 2 && details.displayPageTitles === true; })), Times.atLeastOnce()); - mockProxy.verify(x => x.$openWizard(It.isAny()), Times.once()); + mockProxy.verify(x => x.$openWizard(It.isAny(), It.isAny()), Times.once()); }); test('Wizard page changed events are handled correctly', () => { diff --git a/src/sql/workbench/test/electron-browser/api/mainThreadModelViewDialog.test.ts b/src/sql/workbench/test/electron-browser/api/mainThreadModelViewDialog.test.ts index bbf3e74db1..715c93917c 100644 --- a/src/sql/workbench/test/electron-browser/api/mainThreadModelViewDialog.test.ts +++ b/src/sql/workbench/test/electron-browser/api/mainThreadModelViewDialog.test.ts @@ -52,6 +52,7 @@ suite('MainThreadModelViewDialog Tests', () => { let page2Handle = 12; let wizardHandle = 13; let page3Handle = 14; + let source = 'command palette'; setup(() => { mockExtHostModelViewDialog = Mock.ofInstance({ @@ -73,7 +74,7 @@ suite('MainThreadModelViewDialog Tests', () => { mockDialogService.setup(x => x.showDialog(It.isAny(), undefined, It.isAny())).callback((dialog) => { openedDialog = dialog; }); - mockDialogService.setup(x => x.showWizard(It.isAny(), It.isAny())).callback(wizard => { + mockDialogService.setup(x => x.showWizard(It.isAny(), It.isAny(), It.isAny())).callback(wizard => { openedWizard = wizard; // The actual service will set the page to 0 when it opens the wizard openedWizard.setCurrentPage(0); @@ -247,10 +248,10 @@ suite('MainThreadModelViewDialog Tests', () => { test('Creating a wizard and calling open on it causes a wizard with correct pages and buttons to open', () => { // If I open the wizard - mainThreadModelViewDialog.$openWizard(wizardHandle); + mainThreadModelViewDialog.$openWizard(wizardHandle, source); // Then the opened wizard's content and buttons match what was set - mockDialogService.verify(x => x.showWizard(It.isAny(), It.isAny()), Times.once()); + mockDialogService.verify(x => x.showWizard(It.isAny(), It.isAny(), It.isAny()), Times.once()); assert.notEqual(openedWizard, undefined); assert.equal(openedWizard.title, wizardDetails.title); assert.equal(openedWizard.doneButton.label, okButtonDetails.label); @@ -281,7 +282,7 @@ suite('MainThreadModelViewDialog Tests', () => { mockExtHostModelViewDialog.setup(x => x.$onWizardPageChanged(It.isAny(), It.isAny())); // If I open the wizard and change the page to index 1 - mainThreadModelViewDialog.$openWizard(wizardHandle); + mainThreadModelViewDialog.$openWizard(wizardHandle, source); openedWizard.setCurrentPage(1); // Then a page changed event gets sent to the extension host @@ -314,7 +315,7 @@ suite('MainThreadModelViewDialog Tests', () => { }; // If I open the wizard and then add a page - mainThreadModelViewDialog.$openWizard(wizardHandle); + mainThreadModelViewDialog.$openWizard(wizardHandle, source); mainThreadModelViewDialog.$setWizardPageDetails(page3Handle, page3Details); mainThreadModelViewDialog.$addWizardPage(wizardHandle, page3Handle, 0); @@ -329,7 +330,7 @@ suite('MainThreadModelViewDialog Tests', () => { mockExtHostModelViewDialog.setup(x => x.$updateWizardPageInfo(It.isAny(), It.isAny(), It.isAny())); // If I open the wizard and then remove a page - mainThreadModelViewDialog.$openWizard(wizardHandle); + mainThreadModelViewDialog.$openWizard(wizardHandle, source); mainThreadModelViewDialog.$removeWizardPage(wizardHandle, 0); // Then the updated page info gets sent to the extension host @@ -343,7 +344,7 @@ suite('MainThreadModelViewDialog Tests', () => { mockExtHostModelViewDialog.setup(x => x.$validateNavigation(It.isAny(), It.isAny())); // If I call validateNavigation on the wizard that gets created - mainThreadModelViewDialog.$openWizard(wizardHandle); + mainThreadModelViewDialog.$openWizard(wizardHandle, source); openedWizard.validateNavigation(1); // Then the call gets forwarded to the extension host @@ -351,7 +352,7 @@ suite('MainThreadModelViewDialog Tests', () => { }); test('Adding a message to a wizard fires events on the created wizard', () => { - mainThreadModelViewDialog.$openWizard(wizardHandle); + mainThreadModelViewDialog.$openWizard(wizardHandle, source); let newMessage: DialogMessage; openedWizard.onMessageChange(message => newMessage = message);