Skip to content

Commit 51f82c3

Browse files
committed
Moves AI feedback URI state handling to provider
Consolidates storage and context updates for AI feedback responses from the command layer into the provider, improving separation of concerns and maintainability. Ensures feedback state is managed centrally, reducing duplication and potential for inconsistencies. (#4449)
1 parent d8b764d commit 51f82c3

File tree

2 files changed

+33
-19
lines changed

2 files changed

+33
-19
lines changed

src/commands/aiFeedback.ts

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@ import type { AIResultContext } from '../plus/ai/aiProviderService';
66
import { extractAIResultContext } from '../plus/ai/utils/-webview/ai.utils';
77
import type { QuickPickItemOfT } from '../quickpicks/items/common';
88
import { command } from '../system/-webview/command';
9-
import { setContext } from '../system/-webview/context';
10-
import { UriMap } from '../system/-webview/uriMap';
11-
import type { Deferrable } from '../system/function/debounce';
12-
import { debounce } from '../system/function/debounce';
13-
import { filterMap, map } from '../system/iterable';
9+
import { map } from '../system/iterable';
1410
import { Logger } from '../system/logger';
1511
import { ActiveEditorCommand } from './commandBase';
1612
import { getCommandUri } from './commandBase.utils';
@@ -45,32 +41,20 @@ export class AIFeedbackUnhelpfulCommand extends ActiveEditorCommand {
4541

4642
type UnhelpfulResult = { reasons?: AIFeedbackUnhelpfulReasons[]; custom?: string };
4743

48-
const uriResponses = new UriMap<AIFeedbackEvent['sentiment']>();
49-
let _updateContextDebounced: Deferrable<() => void> | undefined;
50-
5144
async function sendFeedback(container: Container, uri: Uri, sentiment: AIFeedbackEvent['sentiment']): Promise<void> {
5245
const context = extractAIResultContext(container, uri);
5346
if (!context) return;
5447

5548
try {
56-
const previous = uriResponses.get(uri);
49+
const previous = container.aiFeedback.getFeedbackResponse(uri);
5750
if (sentiment === previous) return;
5851

5952
let unhelpful: UnhelpfulResult | undefined;
6053
if (sentiment === 'unhelpful') {
6154
unhelpful = await showUnhelpfulFeedbackPicker();
6255
}
6356

64-
uriResponses.set(uri, sentiment);
65-
_updateContextDebounced ??= debounce(() => {
66-
void setContext('gitlens:tabs:ai:helpful', [
67-
...filterMap(uriResponses, ([uri, sentiment]) => (sentiment === 'helpful' ? uri : undefined)),
68-
]);
69-
void setContext('gitlens:tabs:ai:unhelpful', [
70-
...filterMap(uriResponses, ([uri, sentiment]) => (sentiment === 'unhelpful' ? uri : undefined)),
71-
]);
72-
}, 100);
73-
_updateContextDebounced();
57+
container.aiFeedback.setFeedbackResponse(uri, sentiment);
7458

7559
sendFeedbackEvent(container, { source: 'ai:markdown-preview' }, context, sentiment, unhelpful);
7660
} catch (ex) {

src/telemetry/aiFeedbackProvider.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import type { Disposable, Uri } from 'vscode';
22
import { workspace } from 'vscode';
3+
import type { AIFeedbackEvent } from '../constants.telemetry';
34
import type { AIResultContext } from '../plus/ai/aiProviderService';
45
import { setContext } from '../system/-webview/context';
6+
import { UriMap } from '../system/-webview/uriMap';
57
import type { Deferrable } from '../system/function/debounce';
68
import { debounce } from '../system/function/debounce';
9+
import { filterMap } from '../system/iterable';
710

811
export class AIFeedbackProvider implements Disposable {
912
constructor() {
@@ -26,8 +29,10 @@ export class AIFeedbackProvider implements Disposable {
2629
private readonly _disposables: Disposable[] = [];
2730
dispose(): void {
2831
this._disposables.forEach(d => void d.dispose());
32+
this._uriResponses.clear();
2933
this._changelogFeedbacks.clear();
3034
this._changelogUris.clear();
35+
this._updateFeedbackContextDebounced = undefined;
3136
this._updateChangelogContextDebounced = undefined;
3237
}
3338

@@ -64,4 +69,29 @@ export class AIFeedbackProvider implements Disposable {
6469
private deleteChangelogFeedback(documentUri: string): void {
6570
this._changelogFeedbacks.delete(documentUri);
6671
}
72+
73+
// Storage for AI feedback responses by URI
74+
private readonly _uriResponses = new UriMap<AIFeedbackEvent['sentiment']>();
75+
private _updateFeedbackContextDebounced: Deferrable<() => void> | undefined;
76+
private updateFeedbackContext(): void {
77+
this._updateFeedbackContextDebounced ??= debounce(() => {
78+
void setContext('gitlens:tabs:ai:helpful', [
79+
...filterMap(this._uriResponses, ([uri, sentiment]) => (sentiment === 'helpful' ? uri : undefined)),
80+
]);
81+
void setContext('gitlens:tabs:ai:unhelpful', [
82+
...filterMap(this._uriResponses, ([uri, sentiment]) => (sentiment === 'unhelpful' ? uri : undefined)),
83+
]);
84+
}, 100);
85+
this._updateFeedbackContextDebounced();
86+
}
87+
setFeedbackResponse(uri: Uri, sentiment: AIFeedbackEvent['sentiment']): void {
88+
const previous = this._uriResponses.get(uri);
89+
if (sentiment === previous) return;
90+
91+
this._uriResponses.set(uri, sentiment);
92+
this.updateFeedbackContext();
93+
}
94+
getFeedbackResponse(uri: Uri): AIFeedbackEvent['sentiment'] | undefined {
95+
return this._uriResponses.get(uri);
96+
}
6797
}

0 commit comments

Comments
 (0)