mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 08:03:20 +00:00
refactor(activity): prevent sidebar effects on notification threads
Add revealInSidebar and clearSidebarFilters options to worktree activation functions, allowing notification threads to activate workspaces silently without revealing or filtering the sidebar.
This commit is contained in:
@@ -98,7 +98,9 @@ describe('activity thread host routing', () => {
|
||||
// Bare setActiveWorktree skips setActiveView('terminal'), initial-terminal seeding and
|
||||
// sleeping-session resume — the workspace dispatcher is the only path that runs them.
|
||||
expect(mocks.activateAndRevealWorkspace).toHaveBeenCalledWith(thread.worktree.id, {
|
||||
executionHostId: REMOTE_HOST
|
||||
executionHostId: REMOTE_HOST,
|
||||
revealInSidebar: false,
|
||||
clearSidebarFilters: false
|
||||
})
|
||||
expect(setActiveWorktree).not.toHaveBeenCalled()
|
||||
expect(mocks.activateTabAndFocusPane).toHaveBeenCalledWith(
|
||||
@@ -121,7 +123,9 @@ describe('activity thread host routing', () => {
|
||||
|
||||
expect(setSelectedPaneKey).toHaveBeenCalledWith(thread.paneKey)
|
||||
expect(mocks.activateAndRevealWorkspace).toHaveBeenCalledWith(thread.worktree.id, {
|
||||
executionHostId: REMOTE_HOST
|
||||
executionHostId: REMOTE_HOST,
|
||||
revealInSidebar: false,
|
||||
clearSidebarFilters: false
|
||||
})
|
||||
expect(mocks.activateTabAndFocusPane).toHaveBeenCalledWith(
|
||||
thread.tab.id,
|
||||
@@ -136,7 +140,9 @@ describe('activity thread host routing', () => {
|
||||
makeActions().selectThread(thread)
|
||||
|
||||
expect(mocks.activateAndRevealWorkspace).toHaveBeenCalledWith(thread.worktree.id, {
|
||||
executionHostId: REMOTE_HOST
|
||||
executionHostId: REMOTE_HOST,
|
||||
revealInSidebar: false,
|
||||
clearSidebarFilters: false
|
||||
})
|
||||
expect(mocks.activateTabAndFocusPane).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
@@ -83,7 +83,13 @@ export function createActivityThreadActions({
|
||||
// state of an SSH session that was never revived — has no resident tab until
|
||||
// resumeSleepingAgentSessionsForWorktree/ensureWorktreeHasInitialTerminal run inside here.
|
||||
// Probing tab residency first is what made a remote row click a silent no-op (#16731).
|
||||
if (activateAndRevealWorkspace(thread.worktree.id, { executionHostId }) === false) {
|
||||
if (
|
||||
activateAndRevealWorkspace(thread.worktree.id, {
|
||||
executionHostId,
|
||||
revealInSidebar: false,
|
||||
clearSidebarFilters: false
|
||||
}) === false
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useAppStore } from '@/store'
|
||||
import { activateAndRevealFolderWorkspace, activateAndRevealWorktree } from './worktree-activation'
|
||||
import {
|
||||
activateAndRevealFolderWorkspace,
|
||||
activateAndRevealWorkspace,
|
||||
activateAndRevealWorktree
|
||||
} from './worktree-activation'
|
||||
import { ensureWorktreeHasInitialTerminal } from './worktree-initial-terminal-seeding'
|
||||
import { folderWorkspaceKey } from '../../../shared/workspace-scope'
|
||||
import { toSshExecutionHostId } from '../../../shared/execution-host'
|
||||
@@ -202,6 +206,25 @@ function seedEmptiedFolderWorkspaceOnTwoHosts(): void {
|
||||
}
|
||||
|
||||
describe('activating a folder workspace whose last terminal was closed', () => {
|
||||
it.each(['local', SSH_HOST_ID] as const)(
|
||||
'opens a notification on %s without revealing the folder',
|
||||
(executionHostId) => {
|
||||
seedEmptiedFolderWorkspaceOnTwoHosts()
|
||||
useAppStore.setState({ sidebarBody: 'agents' })
|
||||
|
||||
const result = activateAndRevealWorkspace(FOLDER_KEY, {
|
||||
executionHostId,
|
||||
revealInSidebar: false,
|
||||
clearSidebarFilters: false
|
||||
})
|
||||
|
||||
expect(result).not.toBe(false)
|
||||
expect(useAppStore.getState().activeWorktreeId).toBe(FOLDER_KEY)
|
||||
expect(useAppStore.getState().sidebarBody).toBe('agents')
|
||||
expect(useAppStore.getState().revealWorktreeInSidebar).not.toHaveBeenCalled()
|
||||
}
|
||||
)
|
||||
|
||||
it('re-seeds a terminal when the workspace is opened', () => {
|
||||
seedEmptiedFolderWorkspaceOnTwoHosts()
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ export function activateAndRevealFolderWorkspace(
|
||||
folderWorkspaceId: string,
|
||||
opts?: {
|
||||
sidebarRevealBehavior?: PendingSidebarWorktreeReveal['behavior']
|
||||
revealInSidebar?: boolean
|
||||
startup?: WorktreeStartupPayload
|
||||
runtimeEnvironmentId?: string | null
|
||||
executionHostId?: ExecutionHostId
|
||||
@@ -163,10 +164,11 @@ export function activateAndRevealFolderWorkspace(
|
||||
opts?.providesInitialSurface
|
||||
)
|
||||
|
||||
if (opts?.sidebarRevealBehavior) {
|
||||
state.revealWorktreeInSidebar(workspaceKey, { behavior: opts.sidebarRevealBehavior })
|
||||
} else {
|
||||
state.revealWorktreeInSidebar(workspaceKey)
|
||||
if (opts?.revealInSidebar !== false) {
|
||||
state.revealWorktreeInSidebar(
|
||||
workspaceKey,
|
||||
opts?.sidebarRevealBehavior ? { behavior: opts.sidebarRevealBehavior } : undefined
|
||||
)
|
||||
}
|
||||
|
||||
return { primaryTabId }
|
||||
@@ -346,8 +348,8 @@ export function activateAndRevealWorkspace(
|
||||
opts?: {
|
||||
executionHostId?: ExecutionHostId
|
||||
providesInitialSurface?: boolean
|
||||
/** Worktree-only: folder workspaces are never filter-hidden, so these are dropped there. */
|
||||
revealInSidebar?: boolean
|
||||
/** Worktree-only: folder workspaces are never filter-hidden. */
|
||||
clearSidebarFilters?: boolean
|
||||
}
|
||||
): ActivateAndRevealResult | false {
|
||||
@@ -355,8 +357,7 @@ export function activateAndRevealWorkspace(
|
||||
if (workspaceScope?.type !== 'folder') {
|
||||
return activateAndRevealWorktree(workspaceId, opts)
|
||||
}
|
||||
const { revealInSidebar: _reveal, clearSidebarFilters: _clear, ...folderOpts } = opts ?? {}
|
||||
return activateAndRevealFolderWorkspace(workspaceScope.folderWorkspaceId, folderOpts)
|
||||
return activateAndRevealFolderWorkspace(workspaceScope.folderWorkspaceId, opts)
|
||||
}
|
||||
|
||||
// Why: break the import cycle — nav-history slice (under @/store) can't import activation directly, so register the activator here.
|
||||
|
||||
Reference in New Issue
Block a user