From a413a8214e6c2541ee8380d7ddda688ccd591947 Mon Sep 17 00:00:00 2001 From: David Kutugata Date: Fri, 12 Feb 2021 18:20:21 -0800 Subject: [PATCH 1/3] Refactor surveys and add a new one (#4794) * Refactor surveys and add a new one * add news and lint * lint * lint * PR comments --- .eslintrc.js | 3 - news/1 Enhancements/4726.md | 1 + src/client/activation/serviceRegistry.ts | 4 +- src/client/common/types.ts | 5 +- .../datascience/dataScienceSurveyBanner.ts | 228 +++++++++--- .../insidersNativeNotebookSurveyBanner.ts | 188 ---------- .../datascience/notebook/introStartPage.ts | 2 +- src/client/datascience/serviceRegistry.ts | 2 - src/client/datascience/shiftEnterBanner.ts | 8 +- .../datascienceSurveyBanner.vscode.test.ts | 341 ++++++++++-------- ...sNativeNotebookSurveyBanner.vscode.test.ts | 222 ------------ .../notebook/introStartPage.vscode.test.ts | 2 +- 12 files changed, 392 insertions(+), 614 deletions(-) create mode 100644 news/1 Enhancements/4726.md delete mode 100644 src/client/datascience/insidersNativeNotebookSurveyBanner.ts delete mode 100644 src/test/datascience/insidersNativeNotebookSurveyBanner.vscode.test.ts diff --git a/.eslintrc.js b/.eslintrc.js index 14f0b2d86a7..d053ab70169 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -520,7 +520,6 @@ module.exports = { 'src/client/providers/referenceProvider.ts', 'src/client/providers/terminalProvider.ts', 'src/client/providers/signatureProvider.ts', - 'src/client/activation/serviceRegistry.ts', 'src/client/activation/languageServer/manager.ts', 'src/client/activation/languageServer/languageServerExtension.ts', 'src/client/activation/languageServer/languageServerProxy.ts', @@ -881,8 +880,6 @@ module.exports = { 'src/client/datascience/data-viewing/dataViewerMessageListener.ts', 'src/client/datascience/data-viewing/dataViewerDependencyService.ts', 'src/client/datascience/data-viewing/dataViewerFactory.ts', - 'src/client/datascience/shiftEnterBanner.ts', - 'src/client/datascience/dataScienceSurveyBanner.ts', 'src/client/datascience/webviews/webViewHost.ts', 'src/client/datascience/progress/progressReporter.ts', 'src/client/datascience/progress/messages.ts', diff --git a/news/1 Enhancements/4726.md b/news/1 Enhancements/4726.md new file mode 100644 index 00000000000..ad7d55f2920 --- /dev/null +++ b/news/1 Enhancements/4726.md @@ -0,0 +1 @@ +Add survey for the new Notebboks experience experiment. diff --git a/src/client/activation/serviceRegistry.ts b/src/client/activation/serviceRegistry.ts index 57092a4a92c..32fd42dd8da 100644 --- a/src/client/activation/serviceRegistry.ts +++ b/src/client/activation/serviceRegistry.ts @@ -18,8 +18,8 @@ export function registerTypes(serviceManager: IServiceManager) { IExtensionActivationService, MigrateDataScienceSettingsService ); - serviceManager.addSingleton( - IJupyterExtensionBanner, + serviceManager.addSingleton( + IExtensionSingleActivationService, DataScienceSurveyBanner, BANNER_NAME_DS_SURVEY ); diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 4634d980027..41a533d21e0 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -15,6 +15,7 @@ import { Uri, WorkspaceEdit } from 'vscode'; +import { BannerType } from '../datascience/dataScienceSurveyBanner'; import { LogLevel } from '../logging/levels'; import { CommandsWithoutArgs } from './application/commands'; import { Experiments } from './experiments/groups'; @@ -325,8 +326,8 @@ export interface IBrowserService { export const IJupyterExtensionBanner = Symbol('IJupyterExtensionBanner'); export interface IJupyterExtensionBanner { - enabled: boolean; - showBanner(): Promise; + isEnabled(type: BannerType): boolean; + showBanner(type: BannerType): Promise; } export const BANNER_NAME_DS_SURVEY: string = 'DSSurveyBanner'; export const BANNER_NAME_INTERACTIVE_SHIFTENTER: string = 'InteractiveShiftEnterBanner'; diff --git a/src/client/datascience/dataScienceSurveyBanner.ts b/src/client/datascience/dataScienceSurveyBanner.ts index ce3091baa93..c02f3739d56 100644 --- a/src/client/datascience/dataScienceSurveyBanner.ts +++ b/src/client/datascience/dataScienceSurveyBanner.ts @@ -5,11 +5,17 @@ import { inject, injectable, named } from 'inversify'; import { Event, EventEmitter, UIKind } from 'vscode'; -import { IApplicationEnvironment, IApplicationShell } from '../common/application/types'; +import { IExtensionSingleActivationService } from '../activation/types'; +import { IApplicationEnvironment, IApplicationShell, IVSCodeNotebook } from '../common/application/types'; +import { UseVSCodeNotebookEditorApi } from '../common/constants'; +import { Experiments } from '../common/experiments/groups'; import '../common/extensions'; +import { traceError } from '../common/logger'; import { BANNER_NAME_DS_SURVEY, IBrowserService, + IDisposableRegistry, + IExperimentService, IJupyterExtensionBanner, IPersistentState, IPersistentStateFactory @@ -18,7 +24,8 @@ import * as localize from '../common/utils/localize'; import { noop } from '../common/utils/misc'; import { MillisecondsInADay } from '../constants'; import { InteractiveWindowMessages, IReExecuteCells } from './interactive-common/interactiveWindowTypes'; -import { IInteractiveWindowListener, INotebookEditorProvider } from './types'; +import { KernelState, KernelStateEventArgs } from './notebookExtensibility'; +import { IInteractiveWindowListener, INotebookEditorProvider, INotebookExtensibility } from './types'; export enum DSSurveyStateKeys { ShowBanner = 'ShowDSSurveyBanner', @@ -26,6 +33,24 @@ export enum DSSurveyStateKeys { ExecutionCount = 'DS_ExecutionCount' } +export enum InsidersNotebookSurveyStateKeys { + ShowBanner = 'ShowInsidersNotebookSurveyBanner', + OpenNotebookCount = 'DS_InsidersNotebookOpenNotebookCount', + ExecutionCount = 'DS_InsidersNotebookExecutionCount' +} + +export enum ExperimentNotebookSurveyStateKeys { + ShowBanner = 'ShowExperimentNotebookSurveyBanner', + OpenNotebookCount = 'DS_ExperimentNotebookOpenNotebookCount', + ExecutionCount = 'DS_ExperimentNotebookExecutionCount' +} + +export enum BannerType { + DSSurvey, + InsidersNotebookSurvey, + ExperimentNotebookSurvey +} + enum DSSurveyLabelIndex { Yes, No @@ -61,7 +86,7 @@ export class DataScienceSurveyBannerLogger implements IInteractiveWindowListener .updateValue(state.value + args.cellIds.length) .then(() => { // On every update try to show the banner. - return this.dataScienceSurveyBanner.showBanner(); + return this.dataScienceSurveyBanner.showBanner(BannerType.DSSurvey); }) .ignoreErrors(); } @@ -87,24 +112,50 @@ export type ShowBannerWithExpiryTime = { expiry?: number; }; @injectable() -export class DataScienceSurveyBanner implements IJupyterExtensionBanner { - public get enabled(): boolean { - if (this.applicationEnvironment.uiKind !== UIKind.Desktop || this.applicationEnvironment.channel !== 'stable') { +export class DataScienceSurveyBanner implements IJupyterExtensionBanner, IExtensionSingleActivationService { + public isEnabled(type: BannerType): boolean { + switch (type) { + case BannerType.InsidersNotebookSurvey: + if (this.useVSCodeNotebookEditorApi && this.applicationEnvironment.channel === 'insiders') { + return this.isEnabledInternal(type); + } + break; + case BannerType.ExperimentNotebookSurvey: + if ( + this.applicationEnvironment.channel === 'stable' && + this.experimentService.inExperiment(Experiments.NativeNotebook) + ) { + return this.isEnabledInternal(type); + } + break; + case BannerType.DSSurvey: + if (this.applicationEnvironment.channel === 'stable') { + return this.isEnabledInternal(type); + } + break; + default: + traceError('Invalid Banner Type'); + return false; + } + return false; + } + private isEnabledInternal(type: BannerType): boolean { + if (this.applicationEnvironment.uiKind !== UIKind.Desktop) { return false; } - if (!this.showBannerState.value.expiry) { + + if (!this.showBannerState.get(type)!.value.expiry) { return true; } - return this.showBannerState.value.expiry! < Date.now(); + return this.showBannerState.get(type)!.value.expiry! < Date.now(); } + private disabledInCurrentSession: boolean = false; - private bannerMessage: string = localize.DataScienceSurveyBanner.bannerMessage(); private bannerLabels: string[] = [ localize.DataScienceSurveyBanner.bannerLabelYes(), localize.DataScienceSurveyBanner.bannerLabelNo() ]; - private readonly showBannerState: IPersistentState; - private readonly surveyLink: string; + private readonly showBannerState = new Map>(); constructor( @inject(IApplicationShell) private appShell: IApplicationShell, @@ -112,77 +163,166 @@ export class DataScienceSurveyBanner implements IJupyterExtensionBanner { @inject(IBrowserService) private browserService: IBrowserService, @inject(INotebookEditorProvider) editorProvider: INotebookEditorProvider, @inject(IApplicationEnvironment) private applicationEnvironment: IApplicationEnvironment, - surveyLink: string = 'https://aka.ms/pyaisurvey' + @inject(IVSCodeNotebook) private vscodeNotebook: IVSCodeNotebook, + @inject(INotebookExtensibility) private notebookExtensibility: INotebookExtensibility, + @inject(IDisposableRegistry) private disposables: IDisposableRegistry, + @inject(UseVSCodeNotebookEditorApi) private useVSCodeNotebookEditorApi: boolean, + @inject(IExperimentService) private experimentService: IExperimentService ) { - this.surveyLink = surveyLink; - this.showBannerState = this.persistentState.createGlobalPersistentState( - DSSurveyStateKeys.ShowBanner, - { - data: true - } - ); + this.setPersistentState(BannerType.DSSurvey, DSSurveyStateKeys.ShowBanner); + this.setPersistentState(BannerType.InsidersNotebookSurvey, InsidersNotebookSurveyStateKeys.ShowBanner); + this.setPersistentState(BannerType.ExperimentNotebookSurvey, ExperimentNotebookSurveyStateKeys.ShowBanner); editorProvider.onDidOpenNotebookEditor(this.openedNotebook.bind(this)); } - public async showBanner(): Promise { - if (!this.enabled || this.disabledInCurrentSession) { - return; - } - const executionCount: number = this.getExecutionCount(); - const notebookCount: number = this.getOpenNotebookCount(); - const show = this.shouldShowBanner(executionCount, notebookCount); + + public async activate() { + this.vscodeNotebook.onDidOpenNotebookDocument(this.openedNotebook, this, this.disposables); + this.notebookExtensibility.onKernelStateChange(this.kernelStateChanged, this, this.disposables); + } + + public async showBanner(type: BannerType): Promise { + const show = this.shouldShowBanner(type); if (!show) { return; } // Disable for the current session. this.disabledInCurrentSession = true; - const response = await this.appShell.showInformationMessage(this.bannerMessage, ...this.bannerLabels); + + const response = await this.appShell.showInformationMessage(this.getBannerMessage(type), ...this.bannerLabels); switch (response) { case this.bannerLabels[DSSurveyLabelIndex.Yes]: { - await this.launchSurvey(); + await this.launchSurvey(type); // Disable for 6 months - await this.disable(6); + await this.disable(6, type); break; } case this.bannerLabels[DSSurveyLabelIndex.No]: { // Disable for 3 months - await this.disable(3); + await this.disable(3, type); break; } default: } } - public shouldShowBanner(executionCount: number, notebookOpenCount: number) { - if (!this.enabled || this.disabledInCurrentSession) { + private shouldShowBanner(type: BannerType) { + if (!this.isEnabled(type) || this.disabledInCurrentSession) { return false; } - return executionCount >= NotebookExecutionThreshold || notebookOpenCount > NotebookOpenThreshold; + const executionCount: number = this.getExecutionCount(type); + const notebookCount: number = this.getOpenNotebookCount(type); + + return executionCount >= NotebookExecutionThreshold || notebookCount > NotebookOpenThreshold; + } + + private setPersistentState(type: BannerType, val: string): void { + this.showBannerState.set( + type, + this.persistentState.createGlobalPersistentState(val, { + data: true + }) + ); } - public async launchSurvey(): Promise { - this.browserService.launch(this.surveyLink); + private async launchSurvey(type: BannerType): Promise { + this.browserService.launch(this.getSurveyLink(type)); } - private async disable(monthsTillNextPrompt: number) { - await this.showBannerState.updateValue({ + private async disable(monthsTillNextPrompt: number, type: BannerType) { + await this.showBannerState.get(type)!.updateValue({ expiry: monthsTillNextPrompt * 31 * MillisecondsInADay + Date.now(), data: true }); } - private getOpenNotebookCount(): number { - const state = this.persistentState.createGlobalPersistentState(DSSurveyStateKeys.OpenNotebookCount, 0); - return state.value; + private getOpenNotebookCount(type: BannerType): number { + switch (type) { + case BannerType.InsidersNotebookSurvey: + return this.getPersistentState(InsidersNotebookSurveyStateKeys.OpenNotebookCount); + case BannerType.ExperimentNotebookSurvey: + return this.getPersistentState(ExperimentNotebookSurveyStateKeys.OpenNotebookCount); + case BannerType.DSSurvey: + return this.getPersistentState(DSSurveyStateKeys.OpenNotebookCount); + default: + traceError('Invalid Banner type'); + return -1; + } } - private getExecutionCount(): number { - const state = this.persistentState.createGlobalPersistentState(DSSurveyStateKeys.ExecutionCount, 0); + private getExecutionCount(type: BannerType): number { + switch (type) { + case BannerType.InsidersNotebookSurvey: + return this.getPersistentState(InsidersNotebookSurveyStateKeys.ExecutionCount); + case BannerType.ExperimentNotebookSurvey: + return this.getPersistentState(ExperimentNotebookSurveyStateKeys.ExecutionCount); + case BannerType.DSSurvey: + return this.getPersistentState(DSSurveyStateKeys.ExecutionCount); + default: + traceError('Invalid Banner type'); + return -1; + } + } + + private getPersistentState(val: string): number { + const state = this.persistentState.createGlobalPersistentState(val, 0); return state.value; } private async openedNotebook() { - const state = this.persistentState.createGlobalPersistentState(DSSurveyStateKeys.OpenNotebookCount, 0); + void this.updateStateAndShowBanner(DSSurveyStateKeys.OpenNotebookCount, BannerType.DSSurvey); + void this.updateStateAndShowBanner( + InsidersNotebookSurveyStateKeys.OpenNotebookCount, + BannerType.InsidersNotebookSurvey + ); + void this.updateStateAndShowBanner( + ExperimentNotebookSurveyStateKeys.OpenNotebookCount, + BannerType.ExperimentNotebookSurvey + ); + } + + private async kernelStateChanged(kernelStateEvent: KernelStateEventArgs) { + if (kernelStateEvent.state === KernelState.executed) { + void this.updateStateAndShowBanner( + InsidersNotebookSurveyStateKeys.ExecutionCount, + BannerType.InsidersNotebookSurvey + ); + void this.updateStateAndShowBanner( + ExperimentNotebookSurveyStateKeys.ExecutionCount, + BannerType.ExperimentNotebookSurvey + ); + } + } + + private async updateStateAndShowBanner(val: string, banner: BannerType) { + const state = this.persistentState.createGlobalPersistentState(val, 0); await state.updateValue(state.value + 1); - return this.showBanner(); + void this.showBanner(banner); + } + + private getBannerMessage(type: BannerType): string { + switch (type) { + case BannerType.InsidersNotebookSurvey: + case BannerType.ExperimentNotebookSurvey: + return localize.InsidersNativeNotebooksSurveyBanner.bannerMessage(); + case BannerType.DSSurvey: + return localize.DataScienceSurveyBanner.bannerMessage(); + default: + traceError('Invalid Banner type'); + return ''; + } + } + + private getSurveyLink(type: BannerType): string { + switch (type) { + case BannerType.InsidersNotebookSurvey: + return 'https://aka.ms/vscjupyternb'; + case BannerType.ExperimentNotebookSurvey: + return 'https://aka.ms/vscnbexp'; + case BannerType.DSSurvey: + return 'https://aka.ms/pyaisurvey'; + default: + traceError('Invalid Banner type'); + return ''; + } } } diff --git a/src/client/datascience/insidersNativeNotebookSurveyBanner.ts b/src/client/datascience/insidersNativeNotebookSurveyBanner.ts deleted file mode 100644 index b48895e94e5..00000000000 --- a/src/client/datascience/insidersNativeNotebookSurveyBanner.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { inject, injectable } from 'inversify'; -import { UIKind } from 'vscode'; -import { IExtensionSingleActivationService } from '../activation/types'; -import { IApplicationEnvironment, IApplicationShell, IVSCodeNotebook } from '../common/application/types'; -import { UseVSCodeNotebookEditorApi } from '../common/constants'; -import { IBrowserService, IDisposableRegistry, IPersistentState, IPersistentStateFactory } from '../common/types'; -import * as localize from '../common/utils/localize'; -import { MillisecondsInADay } from '../constants'; -import { KernelState, KernelStateEventArgs } from './notebookExtensibility'; -import { INotebookExtensibility } from './types'; - -export enum InsidersNotebookSurveyStateKeys { - ShowBanner = 'ShowInsidersNotebookSurveyBanner', - OpenNotebookCount = 'DS_InsidersNotebookOpenNotebookCount', - ExecutionCount = 'DS_InsidersNotebookExecutionCount' -} - -enum DSSurveyLabelIndex { - Yes, - No, - DontShowAgain -} - -const NotebookOpenThreshold = 5; -const NotebookExecutionThreshold = 100; -export type ShowBannerWithExpiryTime = { - /** - * This value is not used. - * We are only interested in the value for `expiry`. - * This structure is based on the old data for older customers when we used PersistentState class. - */ - data: boolean; - /** - * If this is value `undefined`, then prompt can be displayed. - * If this value is `a number`, then a prompt was displayed at one point in time & - * we need to wait for Date.now() to be greater than that number to display it again. - */ - expiry?: number; -}; - -@injectable() -export class InsidersNativeNotebooksSurveyBanner implements IExtensionSingleActivationService { - private get enabled(): boolean { - if (this.applicationEnvironment.uiKind !== UIKind.Desktop) { - return false; - } - if (!this.showBannerState.value.expiry) { - return true; - } - if (this.showBannerState.value.expiry === -1) { - return false; - } - return this.showBannerState.value.expiry! < Date.now(); - } - - private disabledInCurrentSession = false; - - private bannerMessage: string = localize.InsidersNativeNotebooksSurveyBanner.bannerMessage(); - - private bannerLabels: string[] = [ - localize.DataScienceSurveyBanner.bannerLabelYes(), - localize.DataScienceSurveyBanner.bannerLabelNo(), - localize.Common.doNotShowAgain() - ]; - - private readonly showBannerState: IPersistentState; - - constructor( - @inject(IApplicationShell) private appShell: IApplicationShell, - @inject(IPersistentStateFactory) private persistentState: IPersistentStateFactory, - @inject(IBrowserService) private browserService: IBrowserService, - @inject(IVSCodeNotebook) private vscodeNotebook: IVSCodeNotebook, - @inject(UseVSCodeNotebookEditorApi) private useVSCodeNotebookEditorApi: boolean, - @inject(IApplicationEnvironment) private applicationEnvironment: IApplicationEnvironment, - @inject(INotebookExtensibility) private notebookExtensibility: INotebookExtensibility, - @inject(IDisposableRegistry) private disposables: IDisposableRegistry - ) { - this.showBannerState = this.persistentState.createGlobalPersistentState( - InsidersNotebookSurveyStateKeys.ShowBanner, - { - data: true - } - ); - } - - public async activate() { - this.vscodeNotebook.onDidOpenNotebookDocument(this.openedNotebook, this, this.disposables); - this.notebookExtensibility.onKernelStateChange(this.kernelStateChanged, this, this.disposables); - } - - public async showBanner(): Promise { - if (this.disabledInCurrentSession) { - return; - } - const executionCount: number = this.getExecutionCount(); - const notebookCount: number = this.getOpenNotebookCount(); - const show = await this.shouldShowBanner(executionCount, notebookCount); - if (!show) { - return; - } - // Disable for the current session. - this.disabledInCurrentSession = true; - const response = await this.appShell.showInformationMessage(this.bannerMessage, ...this.bannerLabels); - switch (response) { - case this.bannerLabels[DSSurveyLabelIndex.Yes]: { - await this.launchSurvey(); - // Disable for 6 months - await this.disable(6); - break; - } - case this.bannerLabels[DSSurveyLabelIndex.No]: { - // Disable for 3 months - await this.disable(3); - break; - } - case this.bannerLabels[DSSurveyLabelIndex.DontShowAgain]: { - await this.showBannerState.updateValue({ - expiry: -1, - data: true - }); - break; - } - default: - } - } - - public async shouldShowBanner(executionCount: number, notebookOpenCount: number): Promise { - if (!this.enabled) { - return false; - } - - return ( - this.isInsidersNativeNotebooksUser() && - (executionCount >= NotebookExecutionThreshold || notebookOpenCount > NotebookOpenThreshold) - ); - } - - public async launchSurvey(): Promise { - this.browserService.launch('https://aka.ms/vscjupyternb'); - } - - private isInsidersNativeNotebooksUser() { - return this.useVSCodeNotebookEditorApi && this.applicationEnvironment.channel === 'insiders'; - } - - private getOpenNotebookCount(): number { - const state = this.persistentState.createGlobalPersistentState( - InsidersNotebookSurveyStateKeys.OpenNotebookCount, - 0 - ); - return state.value; - } - - private getExecutionCount(): number { - const state = this.persistentState.createGlobalPersistentState( - InsidersNotebookSurveyStateKeys.ExecutionCount, - 0 - ); - return state.value; - } - - private async disable(monthsTillNextPrompt: number) { - await this.showBannerState.updateValue({ - expiry: monthsTillNextPrompt * 31 * MillisecondsInADay + Date.now(), - data: true - }); - } - - private async openedNotebook() { - const state = this.persistentState.createGlobalPersistentState( - InsidersNotebookSurveyStateKeys.OpenNotebookCount, - 0 - ); - await state.updateValue(state.value + 1); - return this.showBanner(); - } - - private async kernelStateChanged(kernelStateEvent: KernelStateEventArgs) { - if (kernelStateEvent.state === KernelState.executed) { - const state = this.persistentState.createGlobalPersistentState( - InsidersNotebookSurveyStateKeys.ExecutionCount, - 0 - ); - await state.updateValue(state.value + 1); - return this.showBanner(); - } - } -} diff --git a/src/client/datascience/notebook/introStartPage.ts b/src/client/datascience/notebook/introStartPage.ts index c90c1ea1ad8..61f33f02d6f 100644 --- a/src/client/datascience/notebook/introStartPage.ts +++ b/src/client/datascience/notebook/introStartPage.ts @@ -14,7 +14,7 @@ import { CommandSource } from '../../testing/common/constants'; import { Commands } from '../constants'; import { ITrustService } from '../types'; import { swallowExceptions } from '../../common/utils/decorators'; -import { InsidersNotebookSurveyStateKeys } from '../insidersNativeNotebookSurveyBanner'; +import { InsidersNotebookSurveyStateKeys } from '../dataScienceSurveyBanner'; export const IntroduceNativeNotebookDisplayed = 'JVSC_INTRO_NATIVE_NB_DISPLAYED'; diff --git a/src/client/datascience/serviceRegistry.ts b/src/client/datascience/serviceRegistry.ts index 63dc4dacb91..299d49a27e1 100644 --- a/src/client/datascience/serviceRegistry.ts +++ b/src/client/datascience/serviceRegistry.ts @@ -47,7 +47,6 @@ import { ExportToPDF } from './export/exportToPDF'; import { ExportToPython } from './export/exportToPython'; import { ExportUtil } from './export/exportUtil'; import { ExportFormat, IExport, IExportDialog, IExportManager } from './export/types'; -import { InsidersNativeNotebooksSurveyBanner } from './insidersNativeNotebookSurveyBanner'; import { DebugListener } from './interactive-common/debugListener'; import { IntellisenseProvider } from './interactive-common/intellisense/intellisenseProvider'; import { LinkProvider } from './interactive-common/linkProvider'; @@ -347,7 +346,6 @@ export function registerTypes(serviceManager: IServiceManager, inNotebookApiExpe serviceManager.addSingleton(INotebookExtensibility, NotebookExtensibility); serviceManager.addBinding(INotebookExtensibility, INotebookExecutionLogger); serviceManager.addSingleton(IWebviewExtensibility, WebviewExtensibility); - serviceManager.addSingleton(IExtensionSingleActivationService, InsidersNativeNotebooksSurveyBanner); serviceManager.addSingleton(INotebookWatcher, NotebookWatcher); registerNotebookTypes(serviceManager); diff --git a/src/client/datascience/shiftEnterBanner.ts b/src/client/datascience/shiftEnterBanner.ts index 11e85a8ac00..89a7ab23799 100644 --- a/src/client/datascience/shiftEnterBanner.ts +++ b/src/client/datascience/shiftEnterBanner.ts @@ -45,12 +45,12 @@ export class InteractiveShiftEnterBanner implements IJupyterExtensionBanner { } this.initialized = true; - if (!this.enabled) { + if (!this.isEnabled()) { return; } } - public get enabled(): boolean { + public isEnabled(): boolean { return this.persistentState.createGlobalPersistentState( InteractiveShiftEnterStateKeys.ShowBanner, true @@ -58,7 +58,7 @@ export class InteractiveShiftEnterBanner implements IJupyterExtensionBanner { } public async showBanner(): Promise { - if (!this.enabled) { + if (!this.isEnabled()) { return; } @@ -96,7 +96,7 @@ export class InteractiveShiftEnterBanner implements IJupyterExtensionBanner { public async shouldShowBanner(): Promise { const settings = this.configuration.getSettings(); return Promise.resolve( - this.enabled && !this.disabledInCurrentSession && !settings.sendSelectionToInteractiveWindow + this.isEnabled() && !this.disabledInCurrentSession && !settings.sendSelectionToInteractiveWindow ); } diff --git a/src/test/datascience/datascienceSurveyBanner.vscode.test.ts b/src/test/datascience/datascienceSurveyBanner.vscode.test.ts index 12460e7fade..316ea2ea11c 100644 --- a/src/test/datascience/datascienceSurveyBanner.vscode.test.ts +++ b/src/test/datascience/datascienceSurveyBanner.vscode.test.ts @@ -8,161 +8,212 @@ import * as fakeTimers from '@sinonjs/fake-timers'; import * as sinon from 'sinon'; import { anything, instance, mock, when, verify, resetCalls } from 'ts-mockito'; -import { IApplicationEnvironment, IApplicationShell } from '../../client/common/application/types'; -import { IBrowserService, IPersistentState, IPersistentStateFactory } from '../../client/common/types'; +import { IApplicationEnvironment, IApplicationShell, IVSCodeNotebook } from '../../client/common/application/types'; import { + IBrowserService, + IExperimentService, + IPersistentState, + IPersistentStateFactory +} from '../../client/common/types'; +import { + BannerType, DataScienceSurveyBanner, DSSurveyStateKeys, + InsidersNotebookSurveyStateKeys, ShowBannerWithExpiryTime } from '../../client/datascience/dataScienceSurveyBanner'; -import { INotebookEditorProvider } from '../../client/datascience/types'; +import { INotebookEditorProvider, INotebookExtensibility } from '../../client/datascience/types'; import { initialize } from '../initialize'; import { noop } from '../../client/common/utils/misc'; import { UIKind } from 'vscode'; import * as localize from '../../client/common/utils/localize'; import { MillisecondsInADay } from '../../client/constants'; -suite('DataScience Survey Banner', () => { - let appShell: IApplicationShell; - let browser: IBrowserService; - let bannerService: DataScienceSurveyBanner; - let editorProvider: INotebookEditorProvider; - let persistentStateFactory: IPersistentStateFactory; - let executionCountState: IPersistentState; - let openNotebookCountState: IPersistentState; - let showBannerState: IPersistentState; - let appEnv: IApplicationEnvironment; - let clock: fakeTimers.InstalledClock; - teardown(() => { - sinon.restore(); - clock.uninstall(); - }); - setup(async () => { - const api = await initialize(); - sinon.restore(); - clock = fakeTimers.install(); - appShell = mock(); - browser = mock(); - editorProvider = mock(); - appEnv = mock(); - persistentStateFactory = mock(); - - when(appEnv.uiKind).thenReturn(UIKind.Desktop); - when(appEnv.channel).thenReturn('stable'); - when(editorProvider.onDidOpenNotebookEditor).thenReturn(noop as any); - const realStateFactory = api.serviceContainer.get(IPersistentStateFactory); - openNotebookCountState = realStateFactory.createGlobalPersistentState( - DSSurveyStateKeys.OpenNotebookCount, - 0 - ); - executionCountState = realStateFactory.createGlobalPersistentState(DSSurveyStateKeys.ExecutionCount, 0); - showBannerState = realStateFactory.createGlobalPersistentState( - DSSurveyStateKeys.ShowBanner, - { data: true } - ); - - when( - persistentStateFactory.createGlobalPersistentState(DSSurveyStateKeys.OpenNotebookCount, anything()) - ).thenReturn(openNotebookCountState); - when( - persistentStateFactory.createGlobalPersistentState(DSSurveyStateKeys.ExecutionCount, anything()) - ).thenReturn(executionCountState); - when(persistentStateFactory.createGlobalPersistentState(DSSurveyStateKeys.ShowBanner, anything())).thenReturn( - showBannerState - ); - when( - persistentStateFactory.createGlobalPersistentState(DSSurveyStateKeys.ShowBanner, anything(), anything()) - ).thenReturn(showBannerState); - - bannerService = createBannerService(); - }); - function createBannerService() { - return new DataScienceSurveyBanner( - instance(appShell), - instance(persistentStateFactory), - instance(browser), - instance(editorProvider), - instance(appEnv) - ); - } - test('Confirm prompt is displayed & only once per session', async () => { - when(appShell.showInformationMessage(anything(), anything(), anything())).thenResolve(); - await showBannerState.updateValue({ data: true }); - await executionCountState.updateValue(100); - - await bannerService.showBanner(); - await bannerService.showBanner(); - await bannerService.showBanner(); - - verify(appShell.showInformationMessage(anything(), anything(), anything())).once(); - }); - test('Confirm prompt is displayed 3 months later', async () => { - when(appShell.showInformationMessage(anything(), anything(), anything())).thenResolve( - localize.DataScienceSurveyBanner.bannerLabelNo() as any - ); - await showBannerState.updateValue({ data: true }); - await executionCountState.updateValue(100); - - await bannerService.showBanner(); - - verify(appShell.showInformationMessage(anything(), anything(), anything())).once(); - resetCalls(appShell); - - // Attempt to display again & it won't. - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything())).never(); - - // Advance time by 1 month & still not displayed. - clock.tick(MillisecondsInADay * 30); - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything())).never(); - - // Advance time by 3.5 month & it will be displayed. - clock.tick(MillisecondsInADay * 30 * 3.5); - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything())).once(); - }); - test('Confirm prompt is displayed 6 months later & survey displayed', async () => { - when(appShell.showInformationMessage(anything(), anything(), anything())).thenResolve( - localize.DataScienceSurveyBanner.bannerLabelYes() as any - ); - - await showBannerState.updateValue({ data: true }); - await executionCountState.updateValue(100); - - await bannerService.showBanner(); - verify(browser.launch(anything())).once(); - verify(appShell.showInformationMessage(anything(), anything(), anything())).once(); - resetCalls(browser); - resetCalls(appShell); - - // Attempt to display again & it won't. - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything())).never(); - - // Advance time by 1 month & still not displayed. - clock.tick(MillisecondsInADay * 30); - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything())).never(); - - // Advance time by 6.5 month & it will be displayed. - clock.tick(MillisecondsInADay * 30 * 6.5); - when(appShell.showInformationMessage(anything(), anything(), anything())).thenResolve( - localize.DataScienceSurveyBanner.bannerLabelNo() as any - ); - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything())).once(); +[true, false].forEach((UseVSCodeNotebookEditorApi) => { + const type = UseVSCodeNotebookEditorApi ? 'Insiders' : 'Stable'; + const survey = UseVSCodeNotebookEditorApi ? BannerType.InsidersNotebookSurvey : BannerType.DSSurvey; + + suite('DataScience Survey Banner - ' + type, () => { + let appShell: IApplicationShell; + let browser: IBrowserService; + let bannerService: DataScienceSurveyBanner; + let editorProvider: INotebookEditorProvider; + let persistentStateFactory: IPersistentStateFactory; + let executionCountState: IPersistentState; + let openNotebookCountState: IPersistentState; + let showBannerState: IPersistentState; + let appEnv: IApplicationEnvironment; + let vscodeNotebook: IVSCodeNotebook; + let notebookExtensibility: INotebookExtensibility; + let experimentService: IExperimentService; + let clock: fakeTimers.InstalledClock; + teardown(() => { + sinon.restore(); + clock.uninstall(); + }); + setup(async () => { + const api = await initialize(); + sinon.restore(); + clock = fakeTimers.install(); + appShell = mock(); + browser = mock(); + editorProvider = mock(); + appEnv = mock(); + persistentStateFactory = mock(); + vscodeNotebook = mock(); + notebookExtensibility = mock(); + experimentService = mock(); + + when(appEnv.uiKind).thenReturn(UIKind.Desktop); + when(appEnv.channel).thenReturn(UseVSCodeNotebookEditorApi ? 'insiders' : 'stable'); + when(editorProvider.onDidOpenNotebookEditor).thenReturn(noop as any); + const realStateFactory = api.serviceContainer.get(IPersistentStateFactory); + openNotebookCountState = realStateFactory.createGlobalPersistentState( + UseVSCodeNotebookEditorApi + ? InsidersNotebookSurveyStateKeys.OpenNotebookCount + : DSSurveyStateKeys.OpenNotebookCount, + 0 + ); + executionCountState = realStateFactory.createGlobalPersistentState( + UseVSCodeNotebookEditorApi + ? InsidersNotebookSurveyStateKeys.ExecutionCount + : DSSurveyStateKeys.ExecutionCount, + 0 + ); + showBannerState = realStateFactory.createGlobalPersistentState( + UseVSCodeNotebookEditorApi ? InsidersNotebookSurveyStateKeys.ShowBanner : DSSurveyStateKeys.ShowBanner, + { data: true } + ); + + when( + persistentStateFactory.createGlobalPersistentState( + UseVSCodeNotebookEditorApi + ? InsidersNotebookSurveyStateKeys.OpenNotebookCount + : DSSurveyStateKeys.OpenNotebookCount, + anything() + ) + ).thenReturn(openNotebookCountState); + when( + persistentStateFactory.createGlobalPersistentState( + UseVSCodeNotebookEditorApi + ? InsidersNotebookSurveyStateKeys.ExecutionCount + : DSSurveyStateKeys.ExecutionCount, + anything() + ) + ).thenReturn(executionCountState); + when( + persistentStateFactory.createGlobalPersistentState( + UseVSCodeNotebookEditorApi + ? InsidersNotebookSurveyStateKeys.ShowBanner + : DSSurveyStateKeys.ShowBanner, + anything() + ) + ).thenReturn(showBannerState); + when( + persistentStateFactory.createGlobalPersistentState( + UseVSCodeNotebookEditorApi + ? InsidersNotebookSurveyStateKeys.ShowBanner + : DSSurveyStateKeys.ShowBanner, + anything(), + anything() + ) + ).thenReturn(showBannerState); + + bannerService = createBannerService(); + }); + function createBannerService() { + return new DataScienceSurveyBanner( + instance(appShell), + instance(persistentStateFactory), + instance(browser), + instance(editorProvider), + instance(appEnv), + instance(vscodeNotebook), + instance(notebookExtensibility), + [], + UseVSCodeNotebookEditorApi, + instance(experimentService) + ); + } + test(type + ' - Confirm prompt is displayed & only once per session', async () => { + when(appShell.showInformationMessage(anything(), anything(), anything())).thenResolve(); + await showBannerState.updateValue({ data: true }); + await executionCountState.updateValue(100); + + await bannerService.showBanner(survey); + await bannerService.showBanner(survey); + await bannerService.showBanner(survey); + + verify(appShell.showInformationMessage(anything(), anything(), anything())).once(); + }); + test(type + ' - Confirm prompt is displayed 3 months later', async () => { + when(appShell.showInformationMessage(anything(), anything(), anything())).thenResolve( + localize.DataScienceSurveyBanner.bannerLabelNo() as any + ); + await showBannerState.updateValue({ data: true }); + await executionCountState.updateValue(100); + + await bannerService.showBanner(survey); + + verify(appShell.showInformationMessage(anything(), anything(), anything())).once(); + resetCalls(appShell); + + // Attempt to display again & it won't. + bannerService = createBannerService(); + await bannerService.showBanner(survey); + verify(browser.launch(anything())).never(); + verify(appShell.showInformationMessage(anything(), anything(), anything())).never(); + + // Advance time by 1 month & still not displayed. + clock.tick(MillisecondsInADay * 30); + bannerService = createBannerService(); + await bannerService.showBanner(survey); + verify(browser.launch(anything())).never(); + verify(appShell.showInformationMessage(anything(), anything(), anything())).never(); + + // Advance time by 3.5 month & it will be displayed. + clock.tick(MillisecondsInADay * 30 * 3.5); + bannerService = createBannerService(); + await bannerService.showBanner(survey); + verify(browser.launch(anything())).never(); + verify(appShell.showInformationMessage(anything(), anything(), anything())).once(); + }); + test(type + ' - Confirm prompt is displayed 6 months later & survey displayed', async () => { + when(appShell.showInformationMessage(anything(), anything(), anything())).thenResolve( + localize.DataScienceSurveyBanner.bannerLabelYes() as any + ); + + await showBannerState.updateValue({ data: true }); + await executionCountState.updateValue(100); + + await bannerService.showBanner(survey); + verify(browser.launch(anything())).once(); + verify(appShell.showInformationMessage(anything(), anything(), anything())).once(); + resetCalls(browser); + resetCalls(appShell); + + // Attempt to display again & it won't. + bannerService = createBannerService(); + await bannerService.showBanner(survey); + verify(browser.launch(anything())).never(); + verify(appShell.showInformationMessage(anything(), anything(), anything())).never(); + + // Advance time by 1 month & still not displayed. + clock.tick(MillisecondsInADay * 30); + bannerService = createBannerService(); + await bannerService.showBanner(survey); + verify(browser.launch(anything())).never(); + verify(appShell.showInformationMessage(anything(), anything(), anything())).never(); + + // Advance time by 6.5 month & it will be displayed. + clock.tick(MillisecondsInADay * 30 * 6.5); + when(appShell.showInformationMessage(anything(), anything(), anything())).thenResolve( + localize.DataScienceSurveyBanner.bannerLabelNo() as any + ); + bannerService = createBannerService(); + await bannerService.showBanner(survey); + verify(browser.launch(anything())).never(); + verify(appShell.showInformationMessage(anything(), anything(), anything())).once(); + }); }); }); diff --git a/src/test/datascience/insidersNativeNotebookSurveyBanner.vscode.test.ts b/src/test/datascience/insidersNativeNotebookSurveyBanner.vscode.test.ts deleted file mode 100644 index 811978ba564..00000000000 --- a/src/test/datascience/insidersNativeNotebookSurveyBanner.vscode.test.ts +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -/* eslint-disable @typescript-eslint/no-explicit-any, */ - -import * as fakeTimers from '@sinonjs/fake-timers'; -import * as sinon from 'sinon'; -import { anything, instance, mock, when, verify, resetCalls } from 'ts-mockito'; -import { IApplicationEnvironment, IApplicationShell, IVSCodeNotebook } from '../../client/common/application/types'; -import { IBrowserService, IPersistentState, IPersistentStateFactory } from '../../client/common/types'; -import { ShowBannerWithExpiryTime } from '../../client/datascience/dataScienceSurveyBanner'; -import { initialize } from '../initialize'; -import { noop } from '../../client/common/utils/misc'; -import { UIKind } from 'vscode'; -import * as localize from '../../client/common/utils/localize'; -import { MillisecondsInADay } from '../../client/constants'; -import { - InsidersNativeNotebooksSurveyBanner, - InsidersNotebookSurveyStateKeys -} from '../../client/datascience/insidersNativeNotebookSurveyBanner'; -import { INotebookExtensibility } from '../../client/datascience/types'; - -suite('Insiders Native Notebooks Survey Banner', () => { - let appShell: IApplicationShell; - let browser: IBrowserService; - let bannerService: InsidersNativeNotebooksSurveyBanner; - let vscNotebook: IVSCodeNotebook; - let persistentStateFactory: IPersistentStateFactory; - let notebookExtensibility: INotebookExtensibility; - let executionCountState: IPersistentState; - let openNotebookCountState: IPersistentState; - let showBannerState: IPersistentState; - let appEnv: IApplicationEnvironment; - let clock: fakeTimers.InstalledClock; - teardown(() => { - sinon.restore(); - clock.uninstall(); - }); - setup(async () => { - const api = await initialize(); - sinon.restore(); - clock = fakeTimers.install(); - appShell = mock(); - browser = mock(); - vscNotebook = mock(); - appEnv = mock(); - persistentStateFactory = mock(); - notebookExtensibility = mock(); - - when(appEnv.uiKind).thenReturn(UIKind.Desktop); - when(appEnv.channel).thenReturn('insiders'); - when(vscNotebook.onDidOpenNotebookDocument(anything(), anything(), anything())).thenReturn(noop as any); - when(notebookExtensibility.onKernelStateChange(anything(), anything(), anything())).thenReturn(noop as any); - const realStateFactory = api.serviceContainer.get(IPersistentStateFactory); - openNotebookCountState = realStateFactory.createGlobalPersistentState( - InsidersNotebookSurveyStateKeys.OpenNotebookCount, - 0 - ); - executionCountState = realStateFactory.createGlobalPersistentState( - InsidersNotebookSurveyStateKeys.ExecutionCount, - 0 - ); - showBannerState = realStateFactory.createGlobalPersistentState( - InsidersNotebookSurveyStateKeys.ShowBanner, - { data: true } - ); - - when( - persistentStateFactory.createGlobalPersistentState( - InsidersNotebookSurveyStateKeys.OpenNotebookCount, - anything() - ) - ).thenReturn(openNotebookCountState); - when( - persistentStateFactory.createGlobalPersistentState( - InsidersNotebookSurveyStateKeys.ExecutionCount, - anything() - ) - ).thenReturn(executionCountState); - when( - persistentStateFactory.createGlobalPersistentState(InsidersNotebookSurveyStateKeys.ShowBanner, anything()) - ).thenReturn(showBannerState); - when( - persistentStateFactory.createGlobalPersistentState( - InsidersNotebookSurveyStateKeys.ShowBanner, - anything(), - anything() - ) - ).thenReturn(showBannerState); - - bannerService = createBannerService(); - }); - function createBannerService() { - return new InsidersNativeNotebooksSurveyBanner( - instance(appShell), - instance(persistentStateFactory), - instance(browser), - instance(vscNotebook), - true, - instance(appEnv), - instance(notebookExtensibility), - [] - ); - } - test('Confirm prompt is displayed & only once per session', async () => { - when(appShell.showInformationMessage(anything(), anything(), anything(), anything())).thenResolve(); - await showBannerState.updateValue({ data: true }); - await executionCountState.updateValue(100); - - await bannerService.showBanner(); - await bannerService.showBanner(); - await bannerService.showBanner(); - - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).once(); - }); - test('Confirm prompt is displayed 3 months later', async () => { - when(appShell.showInformationMessage(anything(), anything(), anything(), anything())).thenResolve( - localize.DataScienceSurveyBanner.bannerLabelNo() as any - ); - await showBannerState.updateValue({ data: true }); - await executionCountState.updateValue(100); - - await bannerService.showBanner(); - - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).once(); - resetCalls(appShell); - - // Attempt to display again & it won't. - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).never(); - - // Advance time by 1 month & still not displayed. - clock.tick(MillisecondsInADay * 30); - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).never(); - - // Advance time by 3.5 month & it will be displayed. - clock.tick(MillisecondsInADay * 30 * 3.5); - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).once(); - }); - test('Confirm prompt is displayed 6 months later & survey displayed', async () => { - when(appShell.showInformationMessage(anything(), anything(), anything(), anything())).thenResolve( - localize.DataScienceSurveyBanner.bannerLabelYes() as any - ); - - await showBannerState.updateValue({ data: true }); - await executionCountState.updateValue(100); - - await bannerService.showBanner(); - verify(browser.launch(anything())).once(); - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).once(); - resetCalls(browser); - resetCalls(appShell); - - // Attempt to display again & it won't. - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).never(); - - // Advance time by 1 month & still not displayed. - clock.tick(MillisecondsInADay * 30); - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).never(); - - // Advance time by 6.5 month & it will be displayed. - clock.tick(MillisecondsInADay * 30 * 6.5); - when(appShell.showInformationMessage(anything(), anything(), anything(), anything())).thenResolve( - localize.DataScienceSurveyBanner.bannerLabelNo() as any - ); - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).once(); - }); - test('Confirm prompt is not displayed again', async () => { - when(appShell.showInformationMessage(anything(), anything(), anything(), anything())).thenResolve( - localize.Common.doNotShowAgain() as any - ); - await showBannerState.updateValue({ data: true }); - await executionCountState.updateValue(100); - - await bannerService.showBanner(); - - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).once(); - resetCalls(appShell); - - // Attempt to display again & it won't. - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).never(); - - // Advance time by 1 month & still not displayed. - clock.tick(MillisecondsInADay * 30); - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).never(); - - // Advance time by 6.5 month & still not displayed. - clock.tick(MillisecondsInADay * 30 * 6.5); - when(appShell.showInformationMessage(anything(), anything(), anything(), anything())).thenResolve( - localize.DataScienceSurveyBanner.bannerLabelNo() as any - ); - bannerService = createBannerService(); - await bannerService.showBanner(); - verify(browser.launch(anything())).never(); - verify(appShell.showInformationMessage(anything(), anything(), anything(), anything())).never(); - }); -}); diff --git a/src/test/datascience/notebook/introStartPage.vscode.test.ts b/src/test/datascience/notebook/introStartPage.vscode.test.ts index 28da92f0b92..08679c708f6 100644 --- a/src/test/datascience/notebook/introStartPage.vscode.test.ts +++ b/src/test/datascience/notebook/introStartPage.vscode.test.ts @@ -9,7 +9,6 @@ import { Memento } from 'vscode'; import { IApplicationEnvironment, ICommandManager } from '../../../client/common/application/types'; import { traceInfo } from '../../../client/common/logger'; import { GLOBAL_MEMENTO, IDisposable, IExtensionContext, IMemento } from '../../../client/common/types'; -import { InsidersNotebookSurveyStateKeys } from '../../../client/datascience/insidersNativeNotebookSurveyBanner'; import { IntroduceNativeNotebookDisplayed, IntroduceNativeNotebookStartPage @@ -18,6 +17,7 @@ import { INotebookEditorProvider, ITrustService } from '../../../client/datascie import { IExtensionTestApi, sleep, waitForCondition } from '../../common'; import { initialize } from '../../initialize'; import { canRunNotebookTests, closeNotebooksAndCleanUpAfterTests } from './helper'; +import { InsidersNotebookSurveyStateKeys } from '../../../client/datascience/dataScienceSurveyBanner'; /* eslint-disable @typescript-eslint/no-explicit-any, no-invalid-this, */ suite('DataScience - VSCode Notebook - Native Notebook Experiment', function () { From b1e98402af584844b76fcf3384b0f8ee697fcb08 Mon Sep 17 00:00:00 2001 From: David Kutugata Date: Fri, 12 Feb 2021 18:24:49 -0800 Subject: [PATCH 2/3] update changelog --- CHANGELOG.md | 4 ++-- news/1 Enhancements/4726.md | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 news/1 Enhancements/4726.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f6278dd59b..e341fbc3aec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,10 +25,10 @@ ([#4550](https://github.com/Microsoft/vscode-jupyter/issues/4550)) 1. Improved Tensor tooltips in Python files which have been run in the interactive window. ([#302](https://github.com/Microsoft/vscode-jupyter/issues/302)) -1. Add do not show again option to the native notebook insiders survey banner. - ([#4658](https://github.com/microsoft/vscode-jupyter/issues/4658)) 1. Minimize number of icons on the notebook toolbar (put the rest in overflow). ([#4730](https://github.com/Microsoft/vscode-jupyter/issues/4730)) +1. Add survey for the new Notebooks experience experiment. + ([#4726](https://github.com/microsoft/vscode-jupyter/issues/4726)) ### Fixes diff --git a/news/1 Enhancements/4726.md b/news/1 Enhancements/4726.md deleted file mode 100644 index ad7d55f2920..00000000000 --- a/news/1 Enhancements/4726.md +++ /dev/null @@ -1 +0,0 @@ -Add survey for the new Notebboks experience experiment. From 70feea1f38232aba11918c308c30c39df7567bb6 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Tue, 16 Feb 2021 12:02:06 -0800 Subject: [PATCH 3/3] Fix IJupyterExtensionBanner service identifier (#4825) --- src/client/activation/serviceRegistry.ts | 9 +++------ src/client/common/types.ts | 5 ++++- src/client/datascience/dataScienceSurveyBanner.ts | 11 +++++------ 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/client/activation/serviceRegistry.ts b/src/client/activation/serviceRegistry.ts index 32fd42dd8da..cc7276ed73f 100644 --- a/src/client/activation/serviceRegistry.ts +++ b/src/client/activation/serviceRegistry.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { BANNER_NAME_DS_SURVEY, BANNER_NAME_INTERACTIVE_SHIFTENTER, IJupyterExtensionBanner } from '../common/types'; +import { BANNER_NAME_INTERACTIVE_SHIFTENTER, IJupyterExtensionBanner, ISurveyBanner } from '../common/types'; import { DataScienceSurveyBanner } from '../datascience/dataScienceSurveyBanner'; import { RecommendPythonExtensionBanner } from '../datascience/recommendPythonExtensionBanner'; import { InteractiveShiftEnterBanner } from '../datascience/shiftEnterBanner'; @@ -18,11 +18,8 @@ export function registerTypes(serviceManager: IServiceManager) { IExtensionActivationService, MigrateDataScienceSettingsService ); - serviceManager.addSingleton( - IExtensionSingleActivationService, - DataScienceSurveyBanner, - BANNER_NAME_DS_SURVEY - ); + serviceManager.addSingleton(ISurveyBanner, DataScienceSurveyBanner); + serviceManager.addBinding(ISurveyBanner, IExtensionSingleActivationService); serviceManager.addSingleton( IJupyterExtensionBanner, InteractiveShiftEnterBanner, diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 41a533d21e0..02d7fd183dd 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -15,6 +15,7 @@ import { Uri, WorkspaceEdit } from 'vscode'; +import { IExtensionSingleActivationService } from '../activation/types'; import { BannerType } from '../datascience/dataScienceSurveyBanner'; import { LogLevel } from '../logging/levels'; import { CommandsWithoutArgs } from './application/commands'; @@ -329,9 +330,11 @@ export interface IJupyterExtensionBanner { isEnabled(type: BannerType): boolean; showBanner(type: BannerType): Promise; } -export const BANNER_NAME_DS_SURVEY: string = 'DSSurveyBanner'; export const BANNER_NAME_INTERACTIVE_SHIFTENTER: string = 'InteractiveShiftEnterBanner'; +export const ISurveyBanner = Symbol('ISurveyBanner'); +export interface ISurveyBanner extends IExtensionSingleActivationService, IJupyterExtensionBanner {} + export type DeprecatedSettingAndValue = { setting: string; values?: {}[]; diff --git a/src/client/datascience/dataScienceSurveyBanner.ts b/src/client/datascience/dataScienceSurveyBanner.ts index c02f3739d56..dd988d1dc82 100644 --- a/src/client/datascience/dataScienceSurveyBanner.ts +++ b/src/client/datascience/dataScienceSurveyBanner.ts @@ -3,7 +3,7 @@ 'use strict'; -import { inject, injectable, named } from 'inversify'; +import { inject, injectable } from 'inversify'; import { Event, EventEmitter, UIKind } from 'vscode'; import { IExtensionSingleActivationService } from '../activation/types'; import { IApplicationEnvironment, IApplicationShell, IVSCodeNotebook } from '../common/application/types'; @@ -12,13 +12,13 @@ import { Experiments } from '../common/experiments/groups'; import '../common/extensions'; import { traceError } from '../common/logger'; import { - BANNER_NAME_DS_SURVEY, IBrowserService, IDisposableRegistry, IExperimentService, IJupyterExtensionBanner, IPersistentState, - IPersistentStateFactory + IPersistentStateFactory, + ISurveyBanner } from '../common/types'; import * as localize from '../common/utils/localize'; import { noop } from '../common/utils/misc'; @@ -65,9 +65,8 @@ export class DataScienceSurveyBannerLogger implements IInteractiveWindowListener private postEmitter = new EventEmitter<{ message: string; payload: any }>(); constructor( @inject(IPersistentStateFactory) private persistentState: IPersistentStateFactory, - @inject(IJupyterExtensionBanner) - @named(BANNER_NAME_DS_SURVEY) - private readonly dataScienceSurveyBanner: IJupyterExtensionBanner + @inject(ISurveyBanner) + private readonly dataScienceSurveyBanner: ISurveyBanner ) {} // eslint-disable-next-line @typescript-eslint/no-explicit-any public get postMessage(): Event<{ message: string; payload: any }> {