Skip to content

Commit 8b04b89

Browse files
committed
Ability to search, sort, and filter Recent Sessions (fix #281349)
1 parent 356911d commit 8b04b89

File tree

4 files changed

+60
-23
lines changed

4 files changed

+60
-23
lines changed

src/vs/platform/actions/common/actions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ export class MenuId {
283283
static readonly MultiDiffEditorFileToolbar = new MenuId('MultiDiffEditorFileToolbar');
284284
static readonly DiffEditorHunkToolbar = new MenuId('DiffEditorHunkToolbar');
285285
static readonly DiffEditorSelectionToolbar = new MenuId('DiffEditorSelectionToolbar');
286-
static readonly AgentSessionsFilterSubMenu = new MenuId('AgentSessionsFilterSubMenu');
286+
static readonly AgentSessionsViewerFilterSubMenu = new MenuId('AgentSessionsViewerFilterSubMenu');
287287
static readonly AgentSessionsInstallMenu = new MenuId('AgentSessionsInstallMenu');
288288
static readonly AgentSessionsContext = new MenuId('AgentSessionsContext');
289289
static readonly AgentSessionsCreateSubMenu = new MenuId('AgentSessionsCreateSubMenu');
@@ -295,6 +295,7 @@ export class MenuId {
295295
* @deprecated TODO@bpasero remove
296296
*/
297297
static readonly AgentSessionsViewTitle = new MenuId('AgentSessionsViewTitle');
298+
static readonly AgentSessionsFilterSubMenu = new MenuId('AgentSessionsFilterSubMenu');
298299

299300
/**
300301
* Create or reuse a `MenuId` with the given identifier

src/vs/workbench/contrib/chat/browser/agentSessions/agentSessions.contribution.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ MenuRegistry.appendMenuItem(MenuId.AgentSessionsViewTitle, {
8383
icon: Codicon.filter
8484
} satisfies ISubmenuItem);
8585

86+
MenuRegistry.appendMenuItem(MenuId.AgentSessionsToolbar, {
87+
submenu: MenuId.AgentSessionsViewerFilterSubMenu,
88+
title: localize2('filterAgentSessions', "Filter Agent Sessions"),
89+
group: 'navigation',
90+
order: 3,
91+
icon: Codicon.filter,
92+
when: ChatContextKeys.agentSessionsViewerExpanded
93+
} satisfies ISubmenuItem);
94+
8695
MenuRegistry.appendMenuItem(MenuId.AgentSessionsToolbar, {
8796
command: {
8897
id: ShowAgentSessionsSidebar.ID,

src/vs/workbench/contrib/chat/browser/agentSessions/agentSessionsFilter.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,16 @@ import { IStorageService, StorageScope, StorageTarget } from '../../../../../pla
1212
import { ChatSessionStatus, IChatSessionsService } from '../../common/chatSessionsService.js';
1313
import { AgentSessionProviders, getAgentSessionProviderName } from './agentSessions.js';
1414
import { IAgentSession } from './agentSessionsModel.js';
15+
import { IAgentSessionsFilter } from './agentSessionsViewer.js';
16+
17+
export interface IAgentSessionsFilterOptions extends Partial<IAgentSessionsFilter> {
1518

16-
export interface IAgentSessionsFilterOptions {
1719
readonly filterMenuId: MenuId;
20+
21+
readonly limitResults?: () => number | undefined;
22+
notifyResults?(count: number): void;
23+
24+
overrideExclude?(session: IAgentSession): boolean | undefined;
1825
}
1926

2027
interface IAgentSessionsViewExcludes {
@@ -29,16 +36,18 @@ const DEFAULT_EXCLUDES: IAgentSessionsViewExcludes = Object.freeze({
2936
archived: true as const,
3037
});
3138

32-
export class AgentSessionsFilter extends Disposable {
39+
export class AgentSessionsFilter extends Disposable implements Required<IAgentSessionsFilter> {
3340

3441
private readonly STORAGE_KEY: string;
3542

3643
private readonly _onDidChange = this._register(new Emitter<void>());
3744
readonly onDidChange = this._onDidChange.event;
3845

46+
readonly limitResults = () => this.options.limitResults?.();
47+
3948
private excludes = DEFAULT_EXCLUDES;
4049

41-
private actionDisposables = this._register(new DisposableStore());
50+
private readonly actionDisposables = this._register(new DisposableStore());
4251

4352
constructor(
4453
private readonly options: IAgentSessionsFilterOptions,
@@ -225,6 +234,11 @@ export class AgentSessionsFilter extends Disposable {
225234
}
226235

227236
exclude(session: IAgentSession): boolean {
237+
const overrideExclude = this.options?.overrideExclude?.(session);
238+
if (typeof overrideExclude === 'boolean') {
239+
return overrideExclude;
240+
}
241+
228242
if (this.excludes.archived && session.isArchived()) {
229243
return true;
230244
}
@@ -239,4 +253,8 @@ export class AgentSessionsFilter extends Disposable {
239253

240254
return false;
241255
}
256+
257+
notifyResults(count: number): void {
258+
this.options.notifyResults?.(count);
259+
}
242260
}

src/vs/workbench/contrib/chat/browser/chatViewPane.ts

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import { Link } from '../../../../platform/opener/browser/link.js';
5454
import { IProgressService } from '../../../../platform/progress/common/progress.js';
5555
import { ChatViewId } from './chat.js';
5656
import { disposableTimeout } from '../../../../base/common/async.js';
57+
import { AgentSessionsFilter } from './agentSessions/agentSessionsFilter.js';
5758

5859
interface IChatViewPaneState extends Partial<IChatModelInputState> {
5960
sessionId?: string;
@@ -355,26 +356,34 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
355356
menuOptions: { shouldForwardArgs: true }
356357
}));
357358

358-
// Sessions Control
359-
this.sessionsControlContainer = append(sessionsContainer, $('.agent-sessions-control-container'));
360-
this.sessionsControl = this._register(this.instantiationService.createInstance(AgentSessionsControl, this.sessionsControlContainer, {
361-
allowOpenSessionsInPanel: true,
362-
filter: {
363-
limitResults: () => {
364-
return that.sessionsViewerLimited ? ChatViewPane.SESSIONS_LIMIT : undefined;
365-
},
366-
exclude(session) {
367-
if (that.sessionsViewerLimited && session.isArchived()) {
359+
// Sessions Filter
360+
const sessionsFilter = this._register(this.instantiationService.createInstance(AgentSessionsFilter, {
361+
filterMenuId: MenuId.AgentSessionsViewerFilterSubMenu,
362+
limitResults: () => {
363+
return that.sessionsViewerLimited ? ChatViewPane.SESSIONS_LIMIT : undefined;
364+
},
365+
overrideExclude(session) {
366+
if (that.sessionsViewerLimited) {
367+
if (session.isArchived()) {
368368
return true; // exclude archived sessions when limited
369369
}
370370

371371
return false;
372-
},
373-
notifyResults(count: number) {
374-
that.notifySessionsControlChanged(count);
375372
}
373+
374+
return undefined; // leave up to the filter settings
375+
},
376+
notifyResults(count: number) {
377+
that.notifySessionsControlChanged(count);
376378
}
377379
}));
380+
381+
// Sessions Control
382+
this.sessionsControlContainer = append(sessionsContainer, $('.agent-sessions-control-container'));
383+
this.sessionsControl = this._register(this.instantiationService.createInstance(AgentSessionsControl, this.sessionsControlContainer, {
384+
allowOpenSessionsInPanel: true,
385+
filter: sessionsFilter
386+
}));
378387
this._register(this.onDidChangeBodyVisibility(visible => this.sessionsControl?.setVisible(visible)));
379388

380389
toolbar.context = this.sessionsControl;
@@ -429,12 +438,12 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
429438
newSessionsContainerVisible = false; // disabled in settings
430439
} else {
431440

432-
// Sessions control: stacked, compact
441+
// Sessions control: stacked
433442
if (this.sessionsViewerOrientation === AgentSessionsViewerOrientation.Stacked) {
434443
newSessionsContainerVisible =
435-
(!this._widget || this._widget?.isEmpty()) && // chat widget empty
436-
!this.welcomeController?.isShowingWelcome.get() && // welcome not showing
437-
this.sessionsCount > 0; // has sessions
444+
(!this._widget || this._widget?.isEmpty()) && // chat widget empty
445+
!this.welcomeController?.isShowingWelcome.get() && // welcome not showing
446+
this.sessionsCount > 0 || !this.sessionsViewerLimited; // has sessions or is showing all sessions
438447
}
439448

440449
// Sessions control: sidebar
@@ -643,7 +652,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
643652
widthReduction = this.sessionsContainer.offsetWidth;
644653
}
645654

646-
// Show compact (grows with the number of items displayed)
655+
// Show stacked (grows with the number of items displayed)
647656
else {
648657
let sessionsHeight: number;
649658
if (this.sessionsViewerLimited) {
@@ -657,7 +666,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
657666
this.sessionsControl.layout(sessionsHeight, width);
658667

659668
heightReduction = this.sessionsContainer.offsetHeight;
660-
widthReduction = 0; // compact on top of the chat widget
669+
widthReduction = 0; // stacked on top of the chat widget
661670
}
662671

663672
return { heightReduction, widthReduction };

0 commit comments

Comments
 (0)