Skip to content

Commit a8823c3

Browse files
authored
telemetry for lightbulb and move to code actions (microsoft#211323)
* first pass on new telemetry * change click condition to when there are 2 or fewer code actions, list out the code actions * remove excessive calls * cleanup * also log the code action providers * change owner to me * change title to provider
1 parent 84d2ef9 commit a8823c3

File tree

3 files changed

+53
-9
lines changed

3 files changed

+53
-9
lines changed

src/vs/editor/contrib/codeAction/browser/codeAction.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ export async function applyCodeAction(
273273
codeActionKind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The kind (refactor, quickfix) of the applied code action' };
274274
codeActionIsPreferred: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Was the code action marked as being a preferred action?' };
275275
reason: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The kind of action used to trigger apply code action.' };
276-
owner: 'mjbvz';
276+
owner: 'justschen';
277277
comment: 'Event used to gain insights into which code actions are being triggered';
278278
};
279279

src/vs/editor/contrib/codeAction/browser/codeActionController.ts

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import { registerThemingParticipant } from 'vs/platform/theme/common/themeServic
3939
import { CodeActionAutoApply, CodeActionFilter, CodeActionItem, CodeActionKind, CodeActionSet, CodeActionTrigger, CodeActionTriggerSource } from 'vs/editor/contrib/codeAction/common/types';
4040
import { CodeActionModel, CodeActionsState } from 'vs/editor/contrib/codeAction/browser/codeActionModel';
4141
import { HierarchicalKind } from 'vs/base/common/hierarchicalKind';
42+
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
4243

4344

4445
interface IActionShowOptions {
@@ -79,6 +80,7 @@ export class CodeActionController extends Disposable implements IEditorContribut
7980
@IConfigurationService private readonly _configurationService: IConfigurationService,
8081
@IActionWidgetService private readonly _actionWidgetService: IActionWidgetService,
8182
@IInstantiationService private readonly _instantiationService: IInstantiationService,
83+
@ITelemetryService private readonly _telemetryService: ITelemetryService
8284
) {
8385
super();
8486

@@ -105,6 +107,29 @@ export class CodeActionController extends Disposable implements IEditorContribut
105107
}
106108

107109
private async showCodeActionsFromLightbulb(actions: CodeActionSet, at: IAnchor | IPosition): Promise<void> {
110+
111+
// Telemetry for showing code actions from lightbulb. Shows us how often it was clicked.
112+
type ShowCodeActionListEvent = {
113+
codeActionListLength: number;
114+
codeActions: string[];
115+
codeActionProviders: string[];
116+
};
117+
118+
type ShowListEventClassification = {
119+
codeActionListLength: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The length of the code action list from the lightbulb widget.' };
120+
codeActions: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The title of code actions in this menu.' };
121+
codeActionProviders: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The provider of code actions in this menu.' };
122+
owner: 'justschen';
123+
comment: 'Event used to gain insights into what code actions are being shown';
124+
};
125+
126+
this._telemetryService.publicLog2<ShowCodeActionListEvent, ShowListEventClassification>('codeAction.showCodeActionsFromLightbulb', {
127+
codeActionListLength: actions.validActions.length,
128+
codeActions: actions.validActions.map(action => action.action.title),
129+
codeActionProviders: actions.validActions.map(action => action.provider?.displayName ?? ''),
130+
});
131+
132+
108133
if (actions.allAIFixes && actions.validActions.length === 1) {
109134
const actionItem = actions.validActions[0];
110135
const command = actionItem.action.command;
@@ -280,13 +305,32 @@ export class CodeActionController extends Disposable implements IEditorContribut
280305

281306
const delegate: IActionListDelegate<CodeActionItem> = {
282307
onSelect: async (action: CodeActionItem, preview?: boolean) => {
283-
this._applyCodeAction(action, /* retrigger */ true, !!preview, ApplyCodeActionReason.FromCodeActions);
284-
this._actionWidgetService.hide();
308+
this._applyCodeAction(action, /* retrigger */ true, !!preview, options.fromLightbulb ? ApplyCodeActionReason.FromAILightbulb : ApplyCodeActionReason.FromCodeActions);
309+
this._actionWidgetService.hide(false);
285310
currentDecorations.clear();
286311
},
287-
onHide: () => {
312+
onHide: (didCancel?) => {
288313
this._editor?.focus();
289314
currentDecorations.clear();
315+
// Telemetry for showing code actions here. only log on `showLightbulb`. Logs when code action list is quit out.
316+
if (options.fromLightbulb && didCancel !== undefined) {
317+
type ShowCodeActionListEvent = {
318+
codeActionListLength: number;
319+
didCancel: boolean;
320+
};
321+
322+
type ShowListEventClassification = {
323+
codeActionListLength: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The length of the code action list when quit out. Can be from any code action menu.' };
324+
didCancel: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the code action was cancelled or selected.' };
325+
owner: 'justschen';
326+
comment: 'Event used to gain insights into how many valid code actions are being shown';
327+
};
328+
329+
this._telemetryService.publicLog2<ShowCodeActionListEvent, ShowListEventClassification>('codeAction.showCodeActionList.onHide', {
330+
codeActionListLength: actions.validActions.length,
331+
didCancel: didCancel,
332+
});
333+
}
290334
},
291335
onHover: async (action: CodeActionItem, token: CancellationToken) => {
292336
if (token.isCancellationRequested) {

src/vs/platform/actionWidget/browser/actionWidget.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export interface IActionWidgetService {
3636

3737
show<T>(user: string, supportsPreview: boolean, items: readonly IActionListItem<T>[], delegate: IActionListDelegate<T>, anchor: IAnchor, container: HTMLElement | undefined, actionBarActions?: readonly IAction[]): void;
3838

39-
hide(): void;
39+
hide(didCancel?: boolean): void;
4040

4141
readonly isVisible: boolean;
4242
}
@@ -87,8 +87,8 @@ class ActionWidgetService extends Disposable implements IActionWidgetService {
8787
this._list?.value?.focusNext();
8888
}
8989

90-
hide() {
91-
this._list.value?.hide();
90+
hide(didCancel?: boolean) {
91+
this._list.value?.hide(didCancel);
9292
this._list.clear();
9393
}
9494

@@ -139,7 +139,7 @@ class ActionWidgetService extends Disposable implements IActionWidgetService {
139139
widget.style.width = `${width}px`;
140140

141141
const focusTracker = renderDisposables.add(dom.trackFocus(element));
142-
renderDisposables.add(focusTracker.onDidBlur(() => this.hide()));
142+
renderDisposables.add(focusTracker.onDidBlur(() => this.hide(true)));
143143

144144
return renderDisposables;
145145
}
@@ -179,7 +179,7 @@ registerAction2(class extends Action2 {
179179
}
180180

181181
run(accessor: ServicesAccessor): void {
182-
accessor.get(IActionWidgetService).hide();
182+
accessor.get(IActionWidgetService).hide(true);
183183
}
184184
});
185185

0 commit comments

Comments
 (0)