From b6c13509e2ebdb2df0d0393ece4c9e181e1a0e74 Mon Sep 17 00:00:00 2001 From: mrleemurray Date: Tue, 24 Mar 2026 14:21:45 +0000 Subject: [PATCH 1/3] Add "Mark as Done" button to sessions title bar for archiving sessions Co-authored-by: Copilot --- .../browser/media/sessionsTitleBarWidget.css | 30 ++++++++++++++++++ .../browser/sessionsTitleBarWidget.ts | 31 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css b/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css index 567da1a2e66a8..d7151f4ac0699 100644 --- a/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css +++ b/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css @@ -107,3 +107,33 @@ font-variant-numeric: tabular-nums; line-height: 16px; } + +/* "Mark as Done" button */ +.command-center .agent-sessions-titlebar-container .agent-sessions-titlebar-done { + display: flex; + align-items: center; + gap: 4px; + flex-shrink: 0; + cursor: pointer; + padding: 0 6px; + height: 22px; + border: none; + border-radius: 4px; + background: transparent; + color: inherit; + font: inherit; + outline: none; +} + +.command-center .agent-sessions-titlebar-container .agent-sessions-titlebar-done:hover { + background-color: var(--vscode-toolbar-hoverBackground); +} + +.command-center .agent-sessions-titlebar-container .agent-sessions-titlebar-done .codicon { + font-size: 14px; +} + +.command-center .agent-sessions-titlebar-container .agent-sessions-titlebar-done-label { + font-size: 12px; + white-space: nowrap; +} diff --git a/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts b/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts index d568036ca5466..0781faaebd65b 100644 --- a/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts +++ b/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts @@ -197,6 +197,37 @@ export class SessionsTitleBarWidget extends BaseActionViewItem { this._container.appendChild(sessionPill); + // "Mark as Done" button — archives the active session and opens a new one + const activeSession = this.activeSessionService.getActiveSession(); + if (activeSession && !activeSession.isUntitled) { + const agentSession = this.agentSessionsService.getSession(activeSession.resource); + if (agentSession && !agentSession.isArchived()) { + const doneButton = $('button.agent-sessions-titlebar-done') as HTMLButtonElement; + doneButton.type = 'button'; + doneButton.tabIndex = 0; + const doneIcon = $(ThemeIcon.asCSSSelector(Codicon.check)); + doneButton.appendChild(doneIcon); + const doneLabel = $('span.agent-sessions-titlebar-done-label'); + doneLabel.textContent = localize('markAsDone', "Mark as Done"); + doneButton.appendChild(doneLabel); + doneButton.setAttribute('aria-label', localize('markAsDoneAriaLabel', "Mark session as done")); + + this._dynamicDisposables.add(this.hoverService.setupManagedHover( + getDefaultHoverDelegate('mouse'), + doneButton, + localize('markAsDoneTooltip', "Archive this session and start a new one") + )); + + this._dynamicDisposables.add(addDisposableListener(doneButton, EventType.CLICK, (e) => { + e.preventDefault(); + e.stopPropagation(); + agentSession.setArchived(true); + })); + + this._container.appendChild(doneButton); + } + } + // Session count widget (to the left of the pill) — toggles sidebar const countWidget = $('button.agent-sessions-titlebar-count') as HTMLButtonElement; countWidget.type = 'button'; From d39b0d8fa4310af44b6b11a5c5ec5db1b109bb34 Mon Sep 17 00:00:00 2001 From: mrleemurray Date: Tue, 24 Mar 2026 14:24:10 +0000 Subject: [PATCH 2/3] Enhance "Mark as Done" button functionality with focus styles and session state checks Co-authored-by: Copilot --- .../browser/media/sessionsTitleBarWidget.css | 5 +++++ .../sessions/browser/sessionsTitleBarWidget.ts | 15 +++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css b/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css index d7151f4ac0699..601164c142750 100644 --- a/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css +++ b/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css @@ -129,6 +129,11 @@ background-color: var(--vscode-toolbar-hoverBackground); } +.command-center .agent-sessions-titlebar-container .agent-sessions-titlebar-done:focus-visible { + outline: 1px solid var(--vscode-focusBorder); + outline-offset: -1px; +} + .command-center .agent-sessions-titlebar-container .agent-sessions-titlebar-done .codicon { font-size: 14px; } diff --git a/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts b/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts index 0781faaebd65b..5fc8a72881c41 100644 --- a/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts +++ b/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts @@ -131,8 +131,11 @@ export class SessionsTitleBarWidget extends BaseActionViewItem { const icon = this._getActiveSessionIcon(); const repoLabel = this._getRepositoryLabel(); const unreadCount = this._countUnreadSessions(); + const activeSession = this.activeSessionService.getActiveSession(); + const isEstablished = !!activeSession && !activeSession.isUntitled; + const isArchived = isEstablished && !!this.agentSessionsService.getSession(activeSession.resource)?.isArchived(); // Build a render-state key from all displayed data - const renderState = `${icon?.id ?? ''}|${label}|${repoLabel ?? ''}|${unreadCount}`; + const renderState = `${icon?.id ?? ''}|${label}|${repoLabel ?? ''}|${unreadCount}|${isEstablished}|${isArchived}`; // Skip re-render if state hasn't changed if (this._lastRenderState === renderState) { @@ -198,10 +201,9 @@ export class SessionsTitleBarWidget extends BaseActionViewItem { this._container.appendChild(sessionPill); // "Mark as Done" button — archives the active session and opens a new one - const activeSession = this.activeSessionService.getActiveSession(); - if (activeSession && !activeSession.isUntitled) { + if (isEstablished && !isArchived) { const agentSession = this.agentSessionsService.getSession(activeSession.resource); - if (agentSession && !agentSession.isArchived()) { + if (agentSession) { const doneButton = $('button.agent-sessions-titlebar-done') as HTMLButtonElement; doneButton.type = 'button'; doneButton.tabIndex = 0; @@ -212,6 +214,11 @@ export class SessionsTitleBarWidget extends BaseActionViewItem { doneButton.appendChild(doneLabel); doneButton.setAttribute('aria-label', localize('markAsDoneAriaLabel', "Mark session as done")); + this._dynamicDisposables.add(addDisposableListener(doneButton, EventType.MOUSE_DOWN, (e) => { + e.preventDefault(); + e.stopPropagation(); + })); + this._dynamicDisposables.add(this.hoverService.setupManagedHover( getDefaultHoverDelegate('mouse'), doneButton, From bcba64f0fb1165adea0912ac065737d989784636 Mon Sep 17 00:00:00 2001 From: mrleemurray Date: Tue, 24 Mar 2026 15:01:26 +0000 Subject: [PATCH 3/3] style: adjust padding for agent sessions titlebar container and add Mark Session As Done action Co-authored-by: Copilot --- .../browser/media/sessionsTitleBarWidget.css | 37 +--------------- .../sessions/browser/sessions.contribution.ts | 44 ++++++++++++++++++- .../browser/sessionsTitleBarWidget.ts | 40 +---------------- 3 files changed, 45 insertions(+), 76 deletions(-) diff --git a/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css b/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css index 601164c142750..36e5bb61af053 100644 --- a/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css +++ b/src/vs/sessions/contrib/sessions/browser/media/sessionsTitleBarWidget.css @@ -11,7 +11,7 @@ flex-wrap: nowrap; align-items: center; justify-content: flex-start; - padding: 0 16px; + padding-left: 16px; height: 22px; border-radius: 4px; -webkit-app-region: no-drag; @@ -107,38 +107,3 @@ font-variant-numeric: tabular-nums; line-height: 16px; } - -/* "Mark as Done" button */ -.command-center .agent-sessions-titlebar-container .agent-sessions-titlebar-done { - display: flex; - align-items: center; - gap: 4px; - flex-shrink: 0; - cursor: pointer; - padding: 0 6px; - height: 22px; - border: none; - border-radius: 4px; - background: transparent; - color: inherit; - font: inherit; - outline: none; -} - -.command-center .agent-sessions-titlebar-container .agent-sessions-titlebar-done:hover { - background-color: var(--vscode-toolbar-hoverBackground); -} - -.command-center .agent-sessions-titlebar-container .agent-sessions-titlebar-done:focus-visible { - outline: 1px solid var(--vscode-focusBorder); - outline-offset: -1px; -} - -.command-center .agent-sessions-titlebar-container .agent-sessions-titlebar-done .codicon { - font-size: 14px; -} - -.command-center .agent-sessions-titlebar-container .agent-sessions-titlebar-done-label { - font-size: 12px; - white-space: nowrap; -} diff --git a/src/vs/sessions/contrib/sessions/browser/sessions.contribution.ts b/src/vs/sessions/contrib/sessions/browser/sessions.contribution.ts index 14a681d901a8a..29d1542a84617 100644 --- a/src/vs/sessions/contrib/sessions/browser/sessions.contribution.ts +++ b/src/vs/sessions/contrib/sessions/browser/sessions.contribution.ts @@ -14,13 +14,18 @@ import { registerWorkbenchContribution2, WorkbenchPhase } from '../../../../work import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { SessionsTitleBarContribution } from './sessionsTitleBarWidget.js'; import { AgenticSessionsViewPane, SessionsViewId } from './sessionsViewPane.js'; -import { SessionsManagementService, ISessionsManagementService } from './sessionsManagementService.js'; +import { SessionsManagementService, ISessionsManagementService, IsNewChatSessionContext } from './sessionsManagementService.js'; import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js'; +import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js'; import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; import { AgentSessionSection, IAgentSessionSection, isAgentSessionSection } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessionsModel.js'; import { ChatContextKeys } from '../../../../workbench/contrib/chat/common/actions/chatContextKeys.js'; +import { IAgentSessionsService } from '../../../../workbench/contrib/chat/browser/agentSessions/agentSessionsService.js'; import { IViewsService } from '../../../../workbench/services/views/common/viewsService.js'; +import { IsAuxiliaryWindowContext } from '../../../../workbench/common/contextkeys.js'; +import { SessionsWelcomeVisibleContext } from '../../../common/contextkeys.js'; import { NewChatViewPane, SessionsViewId as NewChatViewId } from '../../chat/browser/newChatViewPane.js'; +import { Menus } from '../../../browser/menus.js'; const agentSessionsViewIcon = registerIcon('chat-sessions-icon', Codicon.commentDiscussionSparkle, localize('agentSessionsViewIcon', 'Icon for Agent Sessions View')); const AGENT_SESSIONS_VIEW_TITLE = localize2('agentSessions.view.label', "Sessions"); @@ -55,6 +60,43 @@ registerWorkbenchContribution2(SessionsTitleBarContribution.ID, SessionsTitleBar registerSingleton(ISessionsManagementService, SessionsManagementService, InstantiationType.Delayed); +registerAction2(class MarkSessionAsDoneAction extends Action2 { + + constructor() { + super({ + id: 'agentSession.markAsDone', + title: localize2('markAsDone', "Mark as Done"), + icon: Codicon.check, + menu: [{ + id: Menus.CommandCenter, + order: 102, + when: ContextKeyExpr.and( + IsAuxiliaryWindowContext.negate(), + SessionsWelcomeVisibleContext.negate(), + IsNewChatSessionContext.negate() + ) + }] + }); + } + + async run(accessor: ServicesAccessor): Promise { + const sessionsManagementService = accessor.get(ISessionsManagementService); + const agentSessionsService = accessor.get(IAgentSessionsService); + + const activeSession = sessionsManagementService.getActiveSession(); + if (!activeSession || activeSession.isUntitled) { + return; + } + + const agentSession = agentSessionsService.getSession(activeSession.resource); + if (!agentSession || agentSession.isArchived()) { + return; + } + + agentSession.setArchived(true); + } +}); + registerAction2(class NewSessionForRepositoryAction extends Action2 { constructor() { diff --git a/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts b/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts index 5fc8a72881c41..d568036ca5466 100644 --- a/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts +++ b/src/vs/sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts @@ -131,11 +131,8 @@ export class SessionsTitleBarWidget extends BaseActionViewItem { const icon = this._getActiveSessionIcon(); const repoLabel = this._getRepositoryLabel(); const unreadCount = this._countUnreadSessions(); - const activeSession = this.activeSessionService.getActiveSession(); - const isEstablished = !!activeSession && !activeSession.isUntitled; - const isArchived = isEstablished && !!this.agentSessionsService.getSession(activeSession.resource)?.isArchived(); // Build a render-state key from all displayed data - const renderState = `${icon?.id ?? ''}|${label}|${repoLabel ?? ''}|${unreadCount}|${isEstablished}|${isArchived}`; + const renderState = `${icon?.id ?? ''}|${label}|${repoLabel ?? ''}|${unreadCount}`; // Skip re-render if state hasn't changed if (this._lastRenderState === renderState) { @@ -200,41 +197,6 @@ export class SessionsTitleBarWidget extends BaseActionViewItem { this._container.appendChild(sessionPill); - // "Mark as Done" button — archives the active session and opens a new one - if (isEstablished && !isArchived) { - const agentSession = this.agentSessionsService.getSession(activeSession.resource); - if (agentSession) { - const doneButton = $('button.agent-sessions-titlebar-done') as HTMLButtonElement; - doneButton.type = 'button'; - doneButton.tabIndex = 0; - const doneIcon = $(ThemeIcon.asCSSSelector(Codicon.check)); - doneButton.appendChild(doneIcon); - const doneLabel = $('span.agent-sessions-titlebar-done-label'); - doneLabel.textContent = localize('markAsDone', "Mark as Done"); - doneButton.appendChild(doneLabel); - doneButton.setAttribute('aria-label', localize('markAsDoneAriaLabel', "Mark session as done")); - - this._dynamicDisposables.add(addDisposableListener(doneButton, EventType.MOUSE_DOWN, (e) => { - e.preventDefault(); - e.stopPropagation(); - })); - - this._dynamicDisposables.add(this.hoverService.setupManagedHover( - getDefaultHoverDelegate('mouse'), - doneButton, - localize('markAsDoneTooltip', "Archive this session and start a new one") - )); - - this._dynamicDisposables.add(addDisposableListener(doneButton, EventType.CLICK, (e) => { - e.preventDefault(); - e.stopPropagation(); - agentSession.setArchived(true); - })); - - this._container.appendChild(doneButton); - } - } - // Session count widget (to the left of the pill) — toggles sidebar const countWidget = $('button.agent-sessions-titlebar-count') as HTMLButtonElement; countWidget.type = 'button';