@@ -81,11 +81,12 @@ function createGatewayHarness(client: GatewayBrowserClient) {
8181 } ;
8282 const listeners = new Set < ( next : ApplicationGatewaySnapshot ) => void > ( ) ;
8383 const eventListeners = new Set < ( event : { event : string ; payload : unknown } ) => void > ( ) ;
84+ const setSessionKey = vi . fn ( ) ;
8485 const gateway = {
8586 get snapshot ( ) {
8687 return snapshot ;
8788 } ,
88- setSessionKey : ( ) => undefined ,
89+ setSessionKey,
8990 subscribe ( listener : ( next : ApplicationGatewaySnapshot ) => void ) {
9091 listeners . add ( listener ) ;
9192 return ( ) => listeners . delete ( listener ) ;
@@ -97,6 +98,7 @@ function createGatewayHarness(client: GatewayBrowserClient) {
9798 } as unknown as ApplicationGateway ;
9899 return {
99100 gateway,
101+ setSessionKey,
100102 publish ( patch : Partial < ApplicationGatewaySnapshot > ) {
101103 snapshot = { ...snapshot , ...patch } ;
102104 for ( const listener of listeners ) {
@@ -367,6 +369,21 @@ describe("AppSidebar brand actions", () => {
367369 button ?. click ( ) ;
368370 expect ( onOpenNewSession ) . toHaveBeenCalledExactlyOnceWith ( "research" ) ;
369371 } ) ;
372+
373+ it ( "opens the archived Sessions view from the sessions-zone footer" , async ( ) => {
374+ const gateway = createGateway ( { } as GatewayBrowserClient ) ;
375+ const { sidebar } = await mountSidebar (
376+ gateway ,
377+ createSessions ( "main" , [ "agent:main:main" , "agent:main:work" ] ) ,
378+ ) ;
379+ const onNavigate = vi . fn ( ) ;
380+ sidebar . onNavigate = onNavigate ;
381+ await sidebar . updateComplete ;
382+
383+ sidebar . querySelector < HTMLButtonElement > ( ".sidebar-view-archived" ) ?. click ( ) ;
384+
385+ expect ( onNavigate ) . toHaveBeenCalledWith ( "sessions" , { search : "?showArchived=1" } ) ;
386+ } ) ;
370387} ) ;
371388
372389describe ( "AppSidebar agent chip" , ( ) => {
@@ -3547,6 +3564,55 @@ describe("AppSidebar session mutation feedback", () => {
35473564 link . dispatchEvent ( new MouseEvent ( "click" , { bubbles : true , cancelable : true , metaKey : true } ) ) ;
35483565 }
35493566
3567+ async function mountToastHost ( ) {
3568+ const host = document . createElement ( "openclaw-toast-host" ) ;
3569+ document . body . append ( host ) ;
3570+ await host . updateComplete ;
3571+ return host ;
3572+ }
3573+
3574+ it ( "offers undo after archiving and restores a pinned active session" , async ( ) => {
3575+ const { gateway, harness, sidebar } = await mountMutationHarness ( ) ;
3576+ const state = createSessionState ( "main" , [ "agent:main:main" , "agent:main:a" , "agent:main:b" ] ) ;
3577+ const archivedRow = state . result ?. sessions . find ( ( row ) => row . key === "agent:main:a" ) ;
3578+ if ( ! archivedRow ) {
3579+ throw new Error ( "expected archive row" ) ;
3580+ }
3581+ archivedRow . pinned = true ;
3582+ harness . publishList ( { result : state . result , agentId : state . agentId } ) ;
3583+ gateway . publish ( { sessionKey : archivedRow . key } ) ;
3584+ sidebar . sessionKey = archivedRow . key ;
3585+ ( sidebar as unknown as { activeRouteId : string } ) . activeRouteId = "chat" ;
3586+ const navigate = vi . fn ( ) ;
3587+ sidebar . onNavigate = navigate ;
3588+ const toast = await mountToastHost ( ) ;
3589+ await sidebar . updateComplete ;
3590+
3591+ const menu = await openSessionMenu ( sidebar , archivedRow . key ) ;
3592+ menu . querySelector < HTMLButtonElement > ( '[data-shortcut="a"]' ) ?. click ( ) ;
3593+ await vi . waitFor ( ( ) => expect ( harness . patch ) . toHaveBeenCalledOnce ( ) ) ;
3594+ await vi . waitFor ( ( ) =>
3595+ expect ( toast . querySelector ( ".app-toast__message" ) ?. textContent ) . toBe ( "Session archived" ) ,
3596+ ) ;
3597+ expect ( harness . patch ) . toHaveBeenCalledWith (
3598+ archivedRow . key ,
3599+ { archived : true } ,
3600+ { agentId : "main" } ,
3601+ ) ;
3602+ toast . querySelector < HTMLButtonElement > ( ".app-toast__action" ) ?. click ( ) ;
3603+
3604+ await vi . waitFor ( ( ) => expect ( harness . patch ) . toHaveBeenCalledTimes ( 2 ) ) ;
3605+ await vi . waitFor ( ( ) => expect ( gateway . setSessionKey ) . toHaveBeenLastCalledWith ( archivedRow . key ) ) ;
3606+ expect ( harness . patch ) . toHaveBeenLastCalledWith (
3607+ archivedRow . key ,
3608+ { archived : false , pinned : true } ,
3609+ { agentId : "main" } ,
3610+ ) ;
3611+ expect ( navigate ) . toHaveBeenLastCalledWith ( "chat" , {
3612+ search : "?session=agent%3Amain%3Aa" ,
3613+ } ) ;
3614+ } ) ;
3615+
35503616 it ( "reconciles and stops an idle active cloud worker through its session" , async ( ) => {
35513617 const request = vi . fn ( ( ) => Promise . resolve ( { ok : true } ) ) ;
35523618 const { gateway, harness, sidebar } = await mountMutationHarness ( {
0 commit comments