Skip to content

Commit d3d7b81

Browse files
feat(participant): in-app notification to introduce users to copilot 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
1 parent d739406 commit d3d7b81

File tree

4 files changed

+314
-3
lines changed

4 files changed

+314
-3
lines changed

src/mdbExtensionController.ts

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export default class MDBExtensionController implements vscode.Disposable {
7272
_editDocumentCodeLensProvider: EditDocumentCodeLensProvider;
7373
_exportToLanguageCodeLensProvider: ExportToLanguageCodeLensProvider;
7474
_participantController: ParticipantController;
75+
_startupNotificationShown = false;
7576

7677
constructor(
7778
context: vscode.ExtensionContext,
@@ -166,6 +167,7 @@ export default class MDBExtensionController implements vscode.Disposable {
166167
this.registerCommands();
167168
this.showOverviewPageIfRecentlyInstalled();
168169
void this.showSurveyForEstablishedUsers();
170+
void this.showCopilotIntroductionForEstablishedUsers();
169171
}
170172

171173
registerCommands = (): void => {
@@ -909,23 +911,82 @@ export default class MDBExtensionController implements vscode.Disposable {
909911
}
910912
}
911913

914+
async showCopilotIntroductionForEstablishedUsers(): Promise<void> {
915+
const copilotIntroductionShown =
916+
this._storageController.get(
917+
StorageVariables.GLOBAL_COPILOT_INTRODUCTION_SHOWN
918+
) === true;
919+
920+
// Show the toast when startup notifications have not been shown
921+
// to the user yet and they have saved connections
922+
// -> they haven't just started using this extension.
923+
if (
924+
this._startupNotificationShown ||
925+
copilotIntroductionShown ||
926+
!this._connectionStorage.hasSavedConnections()
927+
) {
928+
return;
929+
}
930+
931+
this._startupNotificationShown = true;
932+
933+
const action = 'Chat with @MongoDB';
934+
const text =
935+
'Generate queries, interact with documentation, and explore your database schema using the MongoDB Copilot extension. Give it a try!';
936+
const result = await vscode.window.showInformationMessage(
937+
text,
938+
{},
939+
{
940+
title: action,
941+
}
942+
);
943+
944+
const copilot = vscode.extensions.getExtension('github.copilot-chat');
945+
if (result?.title === action) {
946+
await vscode.commands.executeCommand('workbench.action.chat.newChat');
947+
await vscode.commands.executeCommand(
948+
'workbench.action.chat.clearHistory'
949+
);
950+
await vscode.commands.executeCommand('workbench.action.chat.open', {
951+
query: '@MongoDB',
952+
isPartialQuery: true,
953+
});
954+
this._telemetryService.trackCopilotIntroductionClicked({
955+
is_copilot_active: !!copilot?.isActive,
956+
});
957+
} else {
958+
this._telemetryService.trackCopilotIntroductionDismissed({
959+
is_copilot_active: !!copilot?.isActive,
960+
});
961+
}
962+
963+
// Whether action was taken or the prompt dismissed, we won't show this again.
964+
void this._storageController.update(
965+
StorageVariables.GLOBAL_COPILOT_INTRODUCTION_SHOWN,
966+
true
967+
);
968+
}
969+
912970
async showSurveyForEstablishedUsers(): Promise<void> {
913971
const surveyId = '9viN9wcbsC3zvHyg7';
914972

915973
const hasBeenShownSurveyAlready =
916974
this._storageController.get(StorageVariables.GLOBAL_SURVEY_SHOWN) ===
917975
surveyId;
918976

919-
// Show the survey when it hasn't been show to the
920-
// user yet, and they have saved connections
977+
// Show the toast when startup notifications have not been shown
978+
// to the user yet and they have saved connections
921979
// -> they haven't just started using this extension
922980
if (
981+
this._startupNotificationShown ||
923982
hasBeenShownSurveyAlready ||
924983
!this._connectionStorage.hasSavedConnections()
925984
) {
926985
return;
927986
}
928987

988+
this._startupNotificationShown = true;
989+
929990
const action = 'Share your thoughts';
930991
const text = 'How can we make the MongoDB extension better for you?';
931992
const link = 'https://forms.gle/9viN9wcbsC3zvHyg7';

src/storage/storageController.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export enum StorageVariables {
77
// Only exists on globalState.
88
GLOBAL_HAS_BEEN_SHOWN_INITIAL_VIEW = 'GLOBAL_HAS_BEEN_SHOWN_INITIAL_VIEW',
99
GLOBAL_SURVEY_SHOWN = 'GLOBAL_SURVEY_SHOWN',
10+
GLOBAL_COPILOT_INTRODUCTION_SHOWN = 'GLOBAL_COPILOT_INTRODUCTION_SHOWN',
1011
GLOBAL_SAVED_CONNECTIONS = 'GLOBAL_SAVED_CONNECTIONS',
1112
// Analytics user identify.
1213
GLOBAL_USER_ID = 'GLOBAL_USER_ID',
@@ -53,6 +54,7 @@ interface StorageVariableContents {
5354
[StorageVariables.GLOBAL_ANONYMOUS_ID]: string;
5455
[StorageVariables.GLOBAL_HAS_BEEN_SHOWN_INITIAL_VIEW]: boolean;
5556
[StorageVariables.GLOBAL_SURVEY_SHOWN]: string;
57+
[StorageVariables.GLOBAL_COPILOT_INTRODUCTION_SHOWN]: boolean;
5658
[StorageVariables.GLOBAL_SAVED_CONNECTIONS]: ConnectionsFromStorage;
5759
[StorageVariables.WORKSPACE_SAVED_CONNECTIONS]: ConnectionsFromStorage;
5860
[StorageVariables.COPILOT_HAS_BEEN_SHOWN_WELCOME_MESSAGE]: boolean;

src/telemetry/telemetryService.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ export type ParticipantResponseProperties = {
126126
output_length: number;
127127
};
128128

129+
export type CopilotIntroductionProperties = {
130+
is_copilot_active: boolean;
131+
};
132+
129133
export function chatResultFeedbackKindToTelemetryValue(
130134
kind: vscode.ChatResultFeedbackKind
131135
): TelemetryFeedbackKind {
@@ -157,7 +161,8 @@ type TelemetryEventProperties =
157161
| ParticipantFeedbackProperties
158162
| ParticipantResponseFailedProperties
159163
| ParticipantPromptProperties
160-
| ParticipantResponseProperties;
164+
| ParticipantResponseProperties
165+
| CopilotIntroductionProperties;
161166

162167
export enum TelemetryEventTypes {
163168
PLAYGROUND_CODE_EXECUTED = 'Playground Code Executed',
@@ -181,6 +186,8 @@ export enum TelemetryEventTypes {
181186
PARTICIPANT_RESPONSE_FAILED = 'Participant Response Failed',
182187
PARTICIPANT_PROMPT_SUBMITTED = 'Participant Prompt Submitted',
183188
PARTICIPANT_RESPONSE_GENERATED = 'Participant Response Generated',
189+
COPILOT_INTRODUCTION_CLICKED = 'Copilot Introduction Clicked',
190+
COPILOT_INTRODUCTION_DISMISSED = 'Copilot Introduction Dismissed',
184191
}
185192

186193
/**
@@ -475,4 +482,14 @@ export default class TelemetryService {
475482
trackCopilotParticipantResponse(props: ParticipantResponseProperties): void {
476483
this.track(TelemetryEventTypes.PARTICIPANT_RESPONSE_GENERATED, props);
477484
}
485+
486+
trackCopilotIntroductionClicked(props: CopilotIntroductionProperties): void {
487+
this.track(TelemetryEventTypes.COPILOT_INTRODUCTION_CLICKED, props);
488+
}
489+
490+
trackCopilotIntroductionDismissed(
491+
props: CopilotIntroductionProperties
492+
): void {
493+
this.track(TelemetryEventTypes.COPILOT_INTRODUCTION_DISMISSED, props);
494+
}
478495
}

0 commit comments

Comments
 (0)