Skip to content

Commit e713699

Browse files
authored
fix(codewhisperer): inline tutorial telemetry (#4632)
1 parent 448bb26 commit e713699

File tree

1 file changed

+43
-22
lines changed

1 file changed

+43
-22
lines changed

packages/core/src/codewhisperer/views/lineAnnotationController.ts

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ function fromId(id: string | undefined): AnnotationState | undefined {
4444
interface AnnotationState {
4545
id: string
4646
suppressWhileRunning: boolean
47+
4748
text: () => string
48-
nextState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState | undefined
49+
updateState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState | undefined
50+
isNextState(state: AnnotationState | undefined): boolean
4951
}
5052

5153
/**
@@ -67,7 +69,7 @@ class AutotriggerState implements AnnotationState {
6769
text = () => 'CodeWhisperer Tip 1/3: Start typing to get suggestions ([ESC] to exit)'
6870
static acceptedCount = 0
6971

70-
nextState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState | undefined {
72+
updateState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState | undefined {
7173
if (AutotriggerState.acceptedCount < RecommendationService.instance.acceptedSuggestionCount) {
7274
return new ManualtriggerState()
7375
} else if (session.recommendations.length > 0 && RecommendationHandler.instance.isSuggestionVisible()) {
@@ -76,6 +78,10 @@ class AutotriggerState implements AnnotationState {
7678
return this
7779
}
7880
}
81+
82+
isNextState(state: AnnotationState | undefined): boolean {
83+
return state instanceof ManualtriggerState
84+
}
7985
}
8086

8187
/**
@@ -92,10 +98,15 @@ class PressTabState implements AnnotationState {
9298
id = PressTabState.id
9399

94100
suppressWhileRunning = false
101+
95102
text = () => 'CodeWhisperer Tip 1/3: Press [TAB] to accept ([ESC] to exit)'
96103

97-
nextState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState | undefined {
98-
return new AutotriggerState().nextState(changeSource, force)
104+
updateState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState | undefined {
105+
return new AutotriggerState().updateState(changeSource, force)
106+
}
107+
108+
isNextState(state: AnnotationState | undefined): boolean {
109+
return state instanceof ManualtriggerState
99110
}
100111
}
101112

@@ -124,7 +135,7 @@ class ManualtriggerState implements AnnotationState {
124135
hasManualTrigger: boolean = false
125136
hasValidResponse: boolean = false
126137

127-
nextState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState | undefined {
138+
updateState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState | undefined {
128139
if (this.hasManualTrigger && this.hasValidResponse) {
129140
if (changeSource !== 'codewhisperer') {
130141
return new TryMoreExState()
@@ -135,6 +146,10 @@ class ManualtriggerState implements AnnotationState {
135146
return this
136147
}
137148
}
149+
150+
isNextState(state: AnnotationState | undefined): boolean {
151+
return state instanceof TryMoreExState
152+
}
138153
}
139154

140155
/**
@@ -153,13 +168,17 @@ class TryMoreExState implements AnnotationState {
153168
suppressWhileRunning = true
154169

155170
text = () => 'CodeWhisperer Tip 3/3: For settings, open the CodeWhisperer menu from the status bar ([ESC] to exit)'
156-
nextState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState {
171+
updateState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState {
157172
if (force) {
158173
return new EndState()
159174
}
160175
return this
161176
}
162177

178+
isNextState(state: AnnotationState | undefined): boolean {
179+
return state instanceof EndState
180+
}
181+
163182
static triggerCount: number = 0
164183
static learnmoeCount: number = 0
165184
}
@@ -170,9 +189,12 @@ class EndState implements AnnotationState {
170189

171190
suppressWhileRunning = true
172191
text = () => ''
173-
nextState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState {
192+
updateState(changeSource: AnnotationChangeSource, force: boolean): AnnotationState {
174193
return this
175194
}
195+
isNextState(state: AnnotationState): boolean {
196+
return false
197+
}
176198
}
177199

178200
/**
@@ -192,8 +214,6 @@ export class LineAnnotationController implements vscode.Disposable {
192214

193215
private _currentState: AnnotationState
194216

195-
private _seen: Set<string> = new Set()
196-
197217
private readonly cwLineHintDecoration: vscode.TextEditorDecorationType =
198218
vscode.window.createTextEditorDecorationType({
199219
after: {
@@ -262,7 +282,7 @@ export class LineAnnotationController implements vscode.Disposable {
262282
try {
263283
telemetry.ui_click.emit({ elementId: `dismiss_${this._currentState.id}` })
264284
} catch (_) {}
265-
await this.markTutorialDone()
285+
await this.dismissTutorial()
266286
getLogger().debug(`codewhisperer: user dismiss tutorial.`)
267287
}
268288
})
@@ -284,7 +304,7 @@ export class LineAnnotationController implements vscode.Disposable {
284304
return this._currentState.id === new EndState().id
285305
}
286306

287-
async markTutorialDone() {
307+
async dismissTutorial() {
288308
this._currentState = new EndState()
289309
await vscode.commands.executeCommand('setContext', inlinehintWipKey, false)
290310
await set(inlinehintKey, this._currentState.id, globals.context.globalState)
@@ -384,14 +404,13 @@ export class LineAnnotationController implements vscode.Disposable {
384404
// special case
385405
// Endstate is meaningless and doesnt need to be rendered
386406
this.clear()
387-
await this.markTutorialDone()
407+
await this.dismissTutorial()
388408
return
389409
} else if (decorationOptions.renderOptions?.after?.contentText === new TryMoreExState().text()) {
390410
// special case
391411
// case 3 exit criteria is to fade away in 30s
392412
setTimeout(async () => {
393-
await this.markTutorialDone()
394-
await this.refresh(editor, source)
413+
await this.refresh(editor, source, true)
395414
}, case3TimeWindow)
396415
}
397416

@@ -423,21 +442,23 @@ export class LineAnnotationController implements vscode.Disposable {
423442
return undefined
424443
}
425444

426-
const nextState: AnnotationState | undefined = this._currentState.nextState(source, force ?? false)
445+
const updatedState: AnnotationState | undefined = this._currentState.updateState(source, force ?? false)
427446

428-
if (nextState === undefined) {
447+
if (updatedState === undefined) {
429448
return undefined
430449
}
431450

432-
if (!this._seen.has(nextState.id)) {
433-
try {
434-
telemetry.ui_click.emit({ elementId: this._currentState.id, passive: true })
435-
} catch (e) {}
451+
if (this._currentState.isNextState(updatedState)) {
452+
// special case because PressTabState is part of case_1 (1a) which possibly jumps directly from case_1a to case_2 and miss case_1
453+
if (this._currentState instanceof PressTabState) {
454+
telemetry.ui_click.emit({ elementId: AutotriggerState.id, passive: true })
455+
}
456+
telemetry.ui_click.emit({ elementId: this._currentState.id, passive: true })
436457
}
437458

438459
// update state
439-
this._currentState = nextState
440-
this._seen.add(this._currentState.id)
460+
this._currentState = updatedState
461+
441462
// take snapshot of accepted session so that we can compre if there is delta -> users accept 1 suggestion after seeing this state
442463
AutotriggerState.acceptedCount = RecommendationService.instance.acceptedSuggestionCount
443464
// take snapshot of total trigger count so that we can compare if there is delta -> users accept/reject suggestions after seeing this state

0 commit comments

Comments
 (0)