fix(app): scope session tab indicators to the tab's server (#34861)

This commit is contained in:
Luke Parker
2026-07-02 16:07:35 +10:00
committed by GitHub
parent 27c9b130c7
commit 1fb2ecc721
7 changed files with 139 additions and 30 deletions
@@ -1,29 +1,41 @@
import { createMemo, type Accessor } from "solid-js"
import { useServerSync } from "@/context/server-sync"
import { useGlobal } from "@/context/global"
import { useNotification } from "@/context/notification"
import { usePermission } from "@/context/permission"
import { ServerConnection } from "@/context/server"
import { sessionPermissionRequest } from "@/pages/session/composer/session-request-tree"
export function useSessionTabAvatarState(
server: Accessor<ServerConnection.Key>,
directory: Accessor<string>,
sessionId: Accessor<string>,
active: Accessor<boolean> = () => true,
) {
const globalSync = useServerSync()
const global = useGlobal()
const notification = useNotification()
const permission = usePermission()
const connection = createMemo(() => global.servers.list().find((item) => ServerConnection.key(item) === server()))
const sync = createMemo(() => {
const conn = connection()
if (conn) return global.ensureServerCtx(conn).sync
})
const hasPermissions = createMemo(() => {
if (!active()) return false
const [store] = globalSync().child(directory(), { bootstrap: false })
return !!sessionPermissionRequest(store.session, globalSync().session.data.permission, sessionId(), (item) => {
const serverSync = sync()
if (!serverSync) return false
const [store] = serverSync.child(directory(), { bootstrap: false })
return !!sessionPermissionRequest(store.session, serverSync.session.data.permission, sessionId(), (item) => {
return !permission.autoResponds(item, directory())
})
})
const unread = createMemo(() => active() && (hasPermissions() || notification.session.unseenCount(sessionId()) > 0))
const unread = createMemo(() => {
if (hasPermissions()) return true
if (!connection()) return false
return notification.ensureServerState(server()).session.unseenCount(sessionId()) > 0
})
const loading = createMemo(() => {
if (!active()) return false
const serverSync = sync()
if (!serverSync) return false
if (hasPermissions()) return false
return globalSync().session.data.session_working(sessionId())
return serverSync.session.data.session_working(sessionId())
})
return { unread, loading }
}
@@ -1,5 +1,6 @@
import type { LocalProject } from "@/context/layout"
import { getProjectAvatarVariant } from "@/context/layout"
import type { ServerConnection } from "@/context/server"
import { displayName, getProjectAvatarSource } from "@/pages/layout/helpers"
import { useSessionTabAvatarState } from "@/pages/layout/project-avatar-state"
import { ProjectAvatar } from "@opencode-ai/ui/v2/project-avatar-v2"
@@ -10,12 +11,14 @@ export function SessionTabAvatar(props: {
project?: LocalProject
directory: string
sessionId: string
activeServer: boolean
server: ServerConnection.Key
revealProjectOnHover?: boolean
}) {
const directory = () => props.directory
const sessionId = () => props.sessionId
const state = useSessionTabAvatarState(directory, sessionId, () => props.activeServer)
const state = useSessionTabAvatarState(
() => props.server,
() => props.directory,
() => props.sessionId,
)
const projectAvatar = () => (
<ProjectAvatar
fallback={displayName(props.project ?? { worktree: props.directory })}