Skip to content

Commit 921b8e5

Browse files
committed
Ability to filter sessions (fix #281349) (#281718)
* Ability to search, sort, and filter `Recent Sessions` (fix #281349) * fix visibility regression
1 parent 6398be6 commit 921b8e5

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
@@ -53,6 +53,7 @@ import { Link } from '../../../../platform/opener/browser/link.js';
5353
import { IProgressService } from '../../../../platform/progress/common/progress.js';
5454
import { ChatViewId } from './chat.js';
5555
import { disposableTimeout } from '../../../../base/common/async.js';
56+
import { AgentSessionsFilter } from './agentSessions/agentSessionsFilter.js';
5657

5758
interface IChatViewPaneState extends Partial<IChatModelInputState> {
5859
sessionId?: string;
@@ -348,26 +349,34 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
348349
menuOptions: { shouldForwardArgs: true }
349350
}));
350351

351-
// Sessions Control
352-
this.sessionsControlContainer = append(sessionsContainer, $('.agent-sessions-control-container'));
353-
this.sessionsControl = this._register(this.instantiationService.createInstance(AgentSessionsControl, this.sessionsControlContainer, {
354-
allowOpenSessionsInPanel: true,
355-
filter: {
356-
limitResults: () => {
357-
return that.sessionsViewerLimited ? ChatViewPane.SESSIONS_LIMIT : undefined;
358-
},
359-
exclude(session) {
360-
if (that.sessionsViewerLimited && session.isArchived()) {
352+
// Sessions Filter
353+
const sessionsFilter = this._register(this.instantiationService.createInstance(AgentSessionsFilter, {
354+
filterMenuId: MenuId.AgentSessionsViewerFilterSubMenu,
355+
limitResults: () => {
356+
return that.sessionsViewerLimited ? ChatViewPane.SESSIONS_LIMIT : undefined;
357+
},
358+
overrideExclude(session) {
359+
if (that.sessionsViewerLimited) {
360+
if (session.isArchived()) {
361361
return true; // exclude archived sessions when limited
362362
}
363363

364364
return false;
365-
},
366-
notifyResults(count: number) {
367-
that.notifySessionsControlChanged(count);
368365
}
366+
367+
return undefined; // leave up to the filter settings
368+
},
369+
notifyResults(count: number) {
370+
that.notifySessionsControlChanged(count);
369371
}
370372
}));
373+
374+
// Sessions Control
375+
this.sessionsControlContainer = append(sessionsContainer, $('.agent-sessions-control-container'));
376+
this.sessionsControl = this._register(this.instantiationService.createInstance(AgentSessionsControl, this.sessionsControlContainer, {
377+
allowOpenSessionsInPanel: true,
378+
filter: sessionsFilter
379+
}));
371380
this._register(this.onDidChangeBodyVisibility(visible => this.sessionsControl?.setVisible(visible)));
372381

373382
toolbar.context = this.sessionsControl;
@@ -422,12 +431,12 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
422431
newSessionsContainerVisible = false; // disabled in settings
423432
} else {
424433

425-
// Sessions control: stacked, compact
434+
// Sessions control: stacked
426435
if (this.sessionsViewerOrientation === AgentSessionsViewerOrientation.Stacked) {
427436
newSessionsContainerVisible =
428-
(!this._widget || this._widget?.isEmpty()) && // chat widget empty
429-
!this.welcomeController?.isShowingWelcome.get() && // welcome not showing
430-
this.sessionsCount > 0; // has sessions
437+
(!this._widget || this._widget?.isEmpty()) && // chat widget empty
438+
!this.welcomeController?.isShowingWelcome.get() && // welcome not showing
439+
(this.sessionsCount > 0 || !this.sessionsViewerLimited); // has sessions or is showing all sessions
431440
}
432441

433442
// Sessions control: sidebar
@@ -636,7 +645,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
636645
widthReduction = this.sessionsContainer.offsetWidth;
637646
}
638647

639-
// Show compact (grows with the number of items displayed)
648+
// Show stacked (grows with the number of items displayed)
640649
else {
641650
let sessionsHeight: number;
642651
if (this.sessionsViewerLimited) {
@@ -650,7 +659,7 @@ export class ChatViewPane extends ViewPane implements IViewWelcomeDelegate {
650659
this.sessionsControl.layout(sessionsHeight, width);
651660

652661
heightReduction = this.sessionsContainer.offsetHeight;
653-
widthReduction = 0; // compact on top of the chat widget
662+
widthReduction = 0; // stacked on top of the chat widget
654663
}
655664

656665
return { heightReduction, widthReduction };

0 commit comments

Comments
 (0)