From 2ba9aa21961697bf9ff5de3b18becaabe56aefd7 Mon Sep 17 00:00:00 2001 From: Erik Demaine Date: Thu, 7 May 2026 23:42:39 -0400 Subject: [PATCH] feat(desktop): working indicator on project sidebar (#26223) --- packages/app/src/pages/layout/sidebar-items.tsx | 12 +++++++++++- packages/app/src/pages/layout/sidebar-project.tsx | 10 +++++++++- .../cli/cmd/tui/component/dialog-session-list.tsx | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/app/src/pages/layout/sidebar-items.tsx b/packages/app/src/pages/layout/sidebar-items.tsx index 296f035ce2..f27a9bb7a9 100644 --- a/packages/app/src/pages/layout/sidebar-items.tsx +++ b/packages/app/src/pages/layout/sidebar-items.tsx @@ -26,7 +26,12 @@ export function getProjectAvatarSource(id?: string, icon?: { color?: string; url return icon?.url } -export const ProjectIcon = (props: { project: LocalProject; class?: string; notify?: boolean }): JSX.Element => { +export const ProjectIcon = (props: { + project: LocalProject + class?: string + notify?: boolean + working?: boolean +}): JSX.Element => { const globalSync = useGlobalSync() const notification = useNotification() const permission = usePermission() @@ -65,6 +70,11 @@ export const ProjectIcon = (props: { project: LocalProject; class?: string; noti }} /> + +
+ +
+
) } diff --git a/packages/app/src/pages/layout/sidebar-project.tsx b/packages/app/src/pages/layout/sidebar-project.tsx index 2ba20092c5..58595c25b9 100644 --- a/packages/app/src/pages/layout/sidebar-project.tsx +++ b/packages/app/src/pages/layout/sidebar-project.tsx @@ -56,6 +56,7 @@ const ProjectTile = (props: { sidebarHovering: Accessor selected: Accessor active: Accessor + isWorking: Accessor overlay: Accessor suppressHover: Accessor dirs: Accessor @@ -143,7 +144,7 @@ const ProjectTile = (props: { }} onBlur={() => props.setOpen(false)} > - + @@ -301,6 +302,12 @@ export const SortableProject = (props: { } const projectStore = createMemo(() => globalSync.child(props.project.worktree, { bootstrap: false })[0]) + const isWorking = createMemo(() => + dirs().some((directory) => { + const [store] = globalSync.child(directory, { bootstrap: false }) + return Object.values(store.session_status).some((status) => status?.type === "busy" || status?.type === "retry") + }), + ) const projectSessions = createMemo(() => sortedRootSessions(projectStore(), props.sortNow())) const workspaceSessions = (directory: string) => { const [data] = globalSync.child(directory, { bootstrap: false }) @@ -313,6 +320,7 @@ export const SortableProject = (props: { sidebarHovering={props.ctx.sidebarHovering} selected={selected} active={active} + isWorking={isWorking} overlay={overlay} suppressHover={() => state.suppressHover} dirs={dirs} diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx index 6d3322151a..542449f5df 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-session-list.tsx @@ -154,7 +154,7 @@ export function DialogSessionList() { } const isDeleting = toDelete() === x.id const status = sync.data.session_status?.[x.id] - const isWorking = status?.type === "busy" + const isWorking = status?.type === "busy" || status?.type === "retry" return { title: isDeleting ? `Press ${deleteHint()} again to confirm` : x.title, bg: isDeleting ? theme.error : undefined,