Skip to content

Commit

Permalink
feat(participant): in-app notification to introduce users to copilot …
Browse files Browse the repository at this point in the history
…extension VSCODE-633 (#875)

* feat(participant): in-app notification to introduce users to copilot extension VSCODE-633

* feat: show copilot introduction only if survey not shown

* feat: startupNotificationShown

* docs: update comments
  • Loading branch information
alenakhineika authored Nov 22, 2024
1 parent d739406 commit d3d7b81
Show file tree
Hide file tree
Showing 4 changed files with 314 additions and 3 deletions.
65 changes: 63 additions & 2 deletions src/mdbExtensionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export default class MDBExtensionController implements vscode.Disposable {
_editDocumentCodeLensProvider: EditDocumentCodeLensProvider;
_exportToLanguageCodeLensProvider: ExportToLanguageCodeLensProvider;
_participantController: ParticipantController;
_startupNotificationShown = false;

constructor(
context: vscode.ExtensionContext,
Expand Down Expand Up @@ -166,6 +167,7 @@ export default class MDBExtensionController implements vscode.Disposable {
this.registerCommands();
this.showOverviewPageIfRecentlyInstalled();
void this.showSurveyForEstablishedUsers();
void this.showCopilotIntroductionForEstablishedUsers();
}

registerCommands = (): void => {
Expand Down Expand Up @@ -909,23 +911,82 @@ export default class MDBExtensionController implements vscode.Disposable {
}
}

async showCopilotIntroductionForEstablishedUsers(): Promise<void> {
const copilotIntroductionShown =
this._storageController.get(
StorageVariables.GLOBAL_COPILOT_INTRODUCTION_SHOWN
) === true;

// Show the toast when startup notifications have not been shown
// to the user yet and they have saved connections
// -> they haven't just started using this extension.
if (
this._startupNotificationShown ||
copilotIntroductionShown ||
!this._connectionStorage.hasSavedConnections()
) {
return;
}

this._startupNotificationShown = true;

const action = 'Chat with @MongoDB';
const text =
'Generate queries, interact with documentation, and explore your database schema using the MongoDB Copilot extension. Give it a try!';
const result = await vscode.window.showInformationMessage(
text,
{},
{
title: action,
}
);

const copilot = vscode.extensions.getExtension('github.copilot-chat');
if (result?.title === action) {
await vscode.commands.executeCommand('workbench.action.chat.newChat');
await vscode.commands.executeCommand(
'workbench.action.chat.clearHistory'
);
await vscode.commands.executeCommand('workbench.action.chat.open', {
query: '@MongoDB',
isPartialQuery: true,
});
this._telemetryService.trackCopilotIntroductionClicked({
is_copilot_active: !!copilot?.isActive,
});
} else {
this._telemetryService.trackCopilotIntroductionDismissed({
is_copilot_active: !!copilot?.isActive,
});
}

// Whether action was taken or the prompt dismissed, we won't show this again.
void this._storageController.update(
StorageVariables.GLOBAL_COPILOT_INTRODUCTION_SHOWN,
true
);
}

async showSurveyForEstablishedUsers(): Promise<void> {
const surveyId = '9viN9wcbsC3zvHyg7';

const hasBeenShownSurveyAlready =
this._storageController.get(StorageVariables.GLOBAL_SURVEY_SHOWN) ===
surveyId;

// Show the survey when it hasn't been show to the
// user yet, and they have saved connections
// Show the toast when startup notifications have not been shown
// to the user yet and they have saved connections
// -> they haven't just started using this extension
if (
this._startupNotificationShown ||
hasBeenShownSurveyAlready ||
!this._connectionStorage.hasSavedConnections()
) {
return;
}

this._startupNotificationShown = true;

const action = 'Share your thoughts';
const text = 'How can we make the MongoDB extension better for you?';
const link = 'https://forms.gle/9viN9wcbsC3zvHyg7';
Expand Down
2 changes: 2 additions & 0 deletions src/storage/storageController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum StorageVariables {
// Only exists on globalState.
GLOBAL_HAS_BEEN_SHOWN_INITIAL_VIEW = 'GLOBAL_HAS_BEEN_SHOWN_INITIAL_VIEW',
GLOBAL_SURVEY_SHOWN = 'GLOBAL_SURVEY_SHOWN',
GLOBAL_COPILOT_INTRODUCTION_SHOWN = 'GLOBAL_COPILOT_INTRODUCTION_SHOWN',
GLOBAL_SAVED_CONNECTIONS = 'GLOBAL_SAVED_CONNECTIONS',
// Analytics user identify.
GLOBAL_USER_ID = 'GLOBAL_USER_ID',
Expand Down Expand Up @@ -53,6 +54,7 @@ interface StorageVariableContents {
[StorageVariables.GLOBAL_ANONYMOUS_ID]: string;
[StorageVariables.GLOBAL_HAS_BEEN_SHOWN_INITIAL_VIEW]: boolean;
[StorageVariables.GLOBAL_SURVEY_SHOWN]: string;
[StorageVariables.GLOBAL_COPILOT_INTRODUCTION_SHOWN]: boolean;
[StorageVariables.GLOBAL_SAVED_CONNECTIONS]: ConnectionsFromStorage;
[StorageVariables.WORKSPACE_SAVED_CONNECTIONS]: ConnectionsFromStorage;
[StorageVariables.COPILOT_HAS_BEEN_SHOWN_WELCOME_MESSAGE]: boolean;
Expand Down
19 changes: 18 additions & 1 deletion src/telemetry/telemetryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ export type ParticipantResponseProperties = {
output_length: number;
};

export type CopilotIntroductionProperties = {
is_copilot_active: boolean;
};

export function chatResultFeedbackKindToTelemetryValue(
kind: vscode.ChatResultFeedbackKind
): TelemetryFeedbackKind {
Expand Down Expand Up @@ -157,7 +161,8 @@ type TelemetryEventProperties =
| ParticipantFeedbackProperties
| ParticipantResponseFailedProperties
| ParticipantPromptProperties
| ParticipantResponseProperties;
| ParticipantResponseProperties
| CopilotIntroductionProperties;

export enum TelemetryEventTypes {
PLAYGROUND_CODE_EXECUTED = 'Playground Code Executed',
Expand All @@ -181,6 +186,8 @@ export enum TelemetryEventTypes {
PARTICIPANT_RESPONSE_FAILED = 'Participant Response Failed',
PARTICIPANT_PROMPT_SUBMITTED = 'Participant Prompt Submitted',
PARTICIPANT_RESPONSE_GENERATED = 'Participant Response Generated',
COPILOT_INTRODUCTION_CLICKED = 'Copilot Introduction Clicked',
COPILOT_INTRODUCTION_DISMISSED = 'Copilot Introduction Dismissed',
}

/**
Expand Down Expand Up @@ -475,4 +482,14 @@ export default class TelemetryService {
trackCopilotParticipantResponse(props: ParticipantResponseProperties): void {
this.track(TelemetryEventTypes.PARTICIPANT_RESPONSE_GENERATED, props);
}

trackCopilotIntroductionClicked(props: CopilotIntroductionProperties): void {
this.track(TelemetryEventTypes.COPILOT_INTRODUCTION_CLICKED, props);
}

trackCopilotIntroductionDismissed(
props: CopilotIntroductionProperties
): void {
this.track(TelemetryEventTypes.COPILOT_INTRODUCTION_DISMISSED, props);
}
}
Loading

0 comments on commit d3d7b81

Please sign in to comment.