Skip to content

Commit 36c2be7

Browse files
authored
Sessions - extract more logic from the view pane (#307911)
1 parent 21cd6ee commit 36c2be7

File tree

1 file changed

+78
-72
lines changed

1 file changed

+78
-72
lines changed

src/vs/sessions/contrib/changes/browser/changesView.ts

Lines changed: 78 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import { IListVirtualDelegate } from '../../../../base/browser/ui/list/list.js';
1010
import { IObjectTreeElement } from '../../../../base/browser/ui/tree/tree.js';
1111
import { ActionRunner, IAction } from '../../../../base/common/actions.js';
1212
import { Codicon } from '../../../../base/common/codicons.js';
13-
import { DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js';
13+
import { Disposable, DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js';
1414
import { Event } from '../../../../base/common/event.js';
15-
import { autorun, derived, IObservable } from '../../../../base/common/observable.js';
15+
import { autorun, derived, derivedOpts, IObservable } from '../../../../base/common/observable.js';
1616
import { basename } from '../../../../base/common/path.js';
1717
import { ProgressBar } from '../../../../base/browser/ui/progressbar/progressbar.js';
1818
import { isEqual } from '../../../../base/common/resources.js';
@@ -69,6 +69,7 @@ import { ActiveSessionContextKeys, CHANGES_VIEW_CONTAINER_ID, CHANGES_VIEW_ID, C
6969
import { buildTreeChildren, ChangesTreeElement, ChangesTreeRenderer, IChangesFileItem, IChangesTreeRootInfo, isChangesFileItem, toIChangesFileItem } from './changesViewRenderer.js';
7070
import { ChangesViewModel } from './changesViewModel.js';
7171
import { ResourceTree } from '../../../../base/common/resourceTree.js';
72+
import { structuralEquals } from '../../../../base/common/equals.js';
7273

7374
const $ = dom.$;
7475

@@ -78,52 +79,100 @@ const RUN_SESSION_CODE_REVIEW_ACTION_ID = 'sessions.codeReview.run';
7879

7980
// --- ButtonBar widget
8081

81-
class ChangesButtonBarWidget extends MenuWorkbenchButtonBar {
82+
class ChangesButtonBarWidget extends Disposable {
8283
constructor(
8384
container: HTMLElement,
84-
sessionResource: URI | undefined,
85-
private readonly outgoingChanges: number,
86-
private readonly codeReviewLoading: boolean,
87-
private readonly reviewCommentCount: number | undefined,
85+
viewModel: ChangesViewModel,
8886
@IAgentSessionsService agentSessionsService: IAgentSessionsService,
8987
@IMenuService menuService: IMenuService,
88+
@ICodeReviewService codeReviewService: ICodeReviewService,
9089
@IContextKeyService contextKeyService: IContextKeyService,
9190
@IContextMenuService contextMenuService: IContextMenuService,
9291
@IKeybindingService keybindingService: IKeybindingService,
9392
@ITelemetryService telemetryService: ITelemetryService,
94-
@IHoverService hoverService: IHoverService,
93+
@IHoverService hoverService: IHoverService
9594
) {
96-
super(
97-
container,
98-
MenuId.ChatEditingSessionChangesToolbar,
99-
{
100-
telemetrySource: 'changesView',
101-
disableWhileRunning: true,
102-
menuOptions: sessionResource
103-
? { args: [sessionResource, agentSessionsService.getSession(sessionResource)?.metadata] }
104-
: { shouldForwardArgs: true },
105-
buttonConfigProvider: (action) => this._getButtonConfiguration(action)
106-
},
107-
menuService, contextKeyService, contextMenuService, keybindingService, telemetryService, hoverService
108-
);
95+
super();
96+
97+
const outgoingChangesObs = derived(reader => {
98+
const activeSessionState = viewModel.activeSessionStateObs.read(reader);
99+
return activeSessionState?.outgoingChanges ?? 0;
100+
});
101+
102+
const reviewStateObs = derivedOpts<{ isLoading: boolean; commentCount: number | undefined }>({ equalsFn: structuralEquals }, reader => {
103+
const sessionResource = viewModel.activeSessionResourceObs.read(reader);
104+
if (!sessionResource) {
105+
return { isLoading: false, commentCount: undefined };
106+
}
107+
108+
const sessionChanges = viewModel.activeSessionChangesObs.read(reader);
109+
const prReviewState = codeReviewService.getPRReviewState(sessionResource).read(reader);
110+
const prReviewCommentCount = prReviewState.kind === PRReviewStateKind.Loaded
111+
? prReviewState.comments.length
112+
: 0;
113+
114+
let isLoading = false;
115+
let commentCount: number | undefined;
116+
if (sessionChanges && sessionChanges.length > 0) {
117+
const reviewFiles = getCodeReviewFilesFromSessionChanges(sessionChanges);
118+
const reviewVersion = getCodeReviewVersion(reviewFiles);
119+
const reviewState = codeReviewService.getReviewState(sessionResource).read(reader);
120+
121+
if (reviewState.kind === CodeReviewStateKind.Loading && reviewState.version === reviewVersion) {
122+
isLoading = true;
123+
} else {
124+
const codeReviewCommentCount = reviewState.kind === CodeReviewStateKind.Result && reviewState.version === reviewVersion
125+
? reviewState.comments.length
126+
: 0;
127+
const totalReviewCommentCount = codeReviewCommentCount + prReviewCommentCount;
128+
if (totalReviewCommentCount > 0) {
129+
commentCount = totalReviewCommentCount;
130+
}
131+
}
132+
} else if (prReviewCommentCount > 0) {
133+
commentCount = prReviewCommentCount;
134+
}
135+
136+
return { isLoading, commentCount };
137+
});
138+
139+
this._register(autorun(reader => {
140+
const sessionResource = viewModel.activeSessionResourceObs.read(reader);
141+
const outgoingChanges = outgoingChangesObs.read(reader);
142+
const reviewState = reviewStateObs.read(reader);
143+
144+
reader.store.add(new MenuWorkbenchButtonBar(
145+
container,
146+
MenuId.ChatEditingSessionChangesToolbar,
147+
{
148+
telemetrySource: 'changesView',
149+
disableWhileRunning: true,
150+
menuOptions: sessionResource
151+
? { args: [sessionResource, agentSessionsService.getSession(sessionResource)?.metadata] }
152+
: { shouldForwardArgs: true },
153+
buttonConfigProvider: (action) => this._getButtonConfiguration(action, outgoingChanges, reviewState)
154+
},
155+
menuService, contextKeyService, contextMenuService, keybindingService, telemetryService, hoverService
156+
));
157+
}));
109158
}
110159

111-
private _getButtonConfiguration(action: IAction): { showIcon: boolean; showLabel: boolean; isSecondary?: boolean; customLabel?: string; customClass?: string } | undefined {
160+
private _getButtonConfiguration(action: IAction, outgoingChanges: number, reviewState: { isLoading: boolean; commentCount: number | undefined }): { showIcon: boolean; showLabel: boolean; isSecondary?: boolean; customLabel?: string; customClass?: string } | undefined {
112161
if (
113162
action.id === 'github.copilot.sessions.sync' ||
114163
action.id === 'github.copilot.chat.createPullRequestCopilotCLIAgentSession.updatePR'
115164
) {
116-
const customLabel = this.outgoingChanges > 0
117-
? `${action.label} ${this.outgoingChanges}↑`
165+
const customLabel = outgoingChanges > 0
166+
? `${action.label} ${outgoingChanges}↑`
118167
: action.label;
119168
return { customLabel, showIcon: true, showLabel: true, isSecondary: false };
120169
}
121170
if (action.id === RUN_SESSION_CODE_REVIEW_ACTION_ID) {
122-
if (this.codeReviewLoading) {
171+
if (reviewState.isLoading) {
123172
return { showIcon: true, showLabel: true, isSecondary: true, customLabel: '$(loading~spin)', customClass: 'code-review-loading' };
124173
}
125-
if (this.reviewCommentCount !== undefined) {
126-
return { showIcon: true, showLabel: true, isSecondary: true, customLabel: String(this.reviewCommentCount), customClass: 'code-review-comments' };
174+
if (reviewState.commentCount !== undefined) {
175+
return { showIcon: true, showLabel: true, isSecondary: true, customLabel: String(reviewState.commentCount), customClass: 'code-review-comments' };
127176
}
128177
return { showIcon: true, showLabel: false, isSecondary: true };
129178
}
@@ -214,7 +263,6 @@ export class ChangesViewPane extends ViewPane {
214263
@IEditorService private readonly editorService: IEditorService,
215264
@ISessionsManagementService private readonly sessionManagementService: ISessionsManagementService,
216265
@ILabelService private readonly labelService: ILabelService,
217-
@ICodeReviewService private readonly codeReviewService: ICodeReviewService,
218266
@ITelemetryService private readonly telemetryService: ITelemetryService,
219267
) {
220268
super({ ...options, titleMenuId: MenuId.ChatEditingSessionTitleToolbar }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, hoverService);
@@ -463,50 +511,8 @@ export class ChangesViewPane extends ViewPane {
463511
const scopedInstantiationService = this.instantiationService.createChild(scopedServiceCollection);
464512
this.renderDisposables.add(scopedInstantiationService);
465513

466-
const outgoingChangesObs = derived(reader => {
467-
const activeSessionState = this.viewModel.activeSessionStateObs.read(reader);
468-
return activeSessionState?.outgoingChanges ?? 0;
469-
});
470-
471-
this.renderDisposables.add(autorun(reader => {
472-
const sessionResource = this.viewModel.activeSessionResourceObs.read(reader);
473-
const outgoingChanges = outgoingChangesObs.read(reader);
474-
475-
// Read code review state to update the button label dynamically
476-
let reviewCommentCount: number | undefined;
477-
let codeReviewLoading = false;
478-
if (sessionResource) {
479-
const prReviewState = this.codeReviewService.getPRReviewState(sessionResource).read(reader);
480-
const prReviewCommentCount = prReviewState.kind === PRReviewStateKind.Loaded ? prReviewState.comments.length : 0;
481-
const activeSession = this.sessionManagementService.activeSession.read(reader);
482-
const sessionChanges = activeSession?.changes.read(reader);
483-
if (sessionChanges && sessionChanges.length > 0) {
484-
const reviewFiles = getCodeReviewFilesFromSessionChanges(sessionChanges);
485-
const reviewVersion = getCodeReviewVersion(reviewFiles);
486-
const reviewState = this.codeReviewService.getReviewState(sessionResource).read(reader);
487-
if (reviewState.kind === CodeReviewStateKind.Loading && reviewState.version === reviewVersion) {
488-
codeReviewLoading = true;
489-
} else {
490-
const codeReviewCommentCount = reviewState.kind === CodeReviewStateKind.Result && reviewState.version === reviewVersion ? reviewState.comments.length : 0;
491-
const totalReviewCommentCount = codeReviewCommentCount + prReviewCommentCount;
492-
if (totalReviewCommentCount > 0) {
493-
reviewCommentCount = totalReviewCommentCount;
494-
}
495-
}
496-
} else if (prReviewCommentCount > 0) {
497-
reviewCommentCount = prReviewCommentCount;
498-
}
499-
}
500-
501-
reader.store.add(scopedInstantiationService.createInstance(
502-
ChangesButtonBarWidget,
503-
this.actionsContainer!,
504-
sessionResource,
505-
outgoingChanges,
506-
codeReviewLoading,
507-
reviewCommentCount
508-
));
509-
}));
514+
this.renderDisposables.add(scopedInstantiationService.createInstance(
515+
ChangesButtonBarWidget, this.actionsContainer, this.viewModel));
510516
}
511517

512518
// Update visibility and file count badge based on entries

0 commit comments

Comments
 (0)