authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-27 14:49:27-08:00
committergravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-02-27 14:49:27-08:00
logbbcf9ba9db15ad02d98c417e3f5566ff2dedf4b7
treee557d3ae749b815007a6d94882c5bd424ca8bf1c
parent3f81f9dcb40dd18ba8a95735ce017dc8b69373c2

Show pending approvals in sidebar thread status

- derive pending approvals from thread activities and label status as "Pending Approval" - remove `isolate` class from chat `SidebarInset` containers

2 files changed, 12 insertions(+), 5 deletions(-)

apps/web/src/components/Sidebar.tsx+10-3
...@@ -15,6 +15,7 @@ import { newCommandId, newProjectId, newThreadId } from "../lib/utils";...@@ -15,6 +15,7 @@ import { newCommandId, newProjectId, newThreadId } from "../lib/utils";
15import { useStore } from "../store";15import { useStore } from "../store";
16import { isChatNewLocalShortcut, isChatNewShortcut } from "../keybindings";16import { isChatNewLocalShortcut, isChatNewShortcut } from "../keybindings";
17import { type Thread } from "../types";17import { type Thread } from "../types";
18import { derivePendingApprovals } from "../session-logic";
18import { gitRemoveWorktreeMutationOptions } from "../lib/gitReactQuery";19import { gitRemoveWorktreeMutationOptions } from "../lib/gitReactQuery";
19import { serverConfigQueryOptions } from "../lib/serverReactQuery";20import { serverConfigQueryOptions } from "../lib/serverReactQuery";
20import { readNativeApi } from "../nativeApi";21import { readNativeApi } from "../nativeApi";
...@@ -50,7 +51,7 @@ function formatRelativeTime(iso: string): string {...@@ -50,7 +51,7 @@ function formatRelativeTime(iso: string): string {
50}51}
5152
52interface ThreadStatusPill {53interface ThreadStatusPill {
53 label: "Working" | "Connecting" | "Completed" | "Awaiting response";54 label: "Working" | "Connecting" | "Completed" | "Pending Approval";
54 colorClass: string;55 colorClass: string;
55 dotClass: string;56 dotClass: string;
56 pulse: boolean;57 pulse: boolean;
...@@ -76,7 +77,7 @@ function hasUnseenCompletion(thread: Thread): boolean {...@@ -76,7 +77,7 @@ function hasUnseenCompletion(thread: Thread): boolean {
76function threadStatusPill(thread: Thread, hasPendingApprovals: boolean): ThreadStatusPill | null {77function threadStatusPill(thread: Thread, hasPendingApprovals: boolean): ThreadStatusPill | null {
77 if (hasPendingApprovals) {78 if (hasPendingApprovals) {
78 return {79 return {
79 label: "Awaiting response",80 label: "Pending Approval",
80 colorClass: "text-amber-600 dark:text-amber-300/90",81 colorClass: "text-amber-600 dark:text-amber-300/90",
81 dotClass: "bg-amber-500 dark:bg-amber-300/90",82 dotClass: "bg-amber-500 dark:bg-amber-300/90",
82 pulse: false,83 pulse: false,
...@@ -158,7 +159,13 @@ export default function Sidebar() {...@@ -158,7 +159,13 @@ export default function Sidebar() {
158 const [newCwd, setNewCwd] = useState("");159 const [newCwd, setNewCwd] = useState("");
159 const [isPickingFolder, setIsPickingFolder] = useState(false);160 const [isPickingFolder, setIsPickingFolder] = useState(false);
160 const [isAddingProject, setIsAddingProject] = useState(false);161 const [isAddingProject, setIsAddingProject] = useState(false);
161 const pendingApprovalByThreadId = useMemo(() => new Map<ThreadId, boolean>(), []);162 const pendingApprovalByThreadId = useMemo(() => {
163 const map = new Map<ThreadId, boolean>();
164 for (const thread of state.threads) {
165 map.set(thread.id, derivePendingApprovals(thread.activities).length > 0);
166 }
167 return map;
168 }, [state.threads]);
162169
163 const handleNewThread = useCallback(170 const handleNewThread = useCallback(
164 (171 (
apps/web/src/routes/_chat.$threadId.tsx+2-2
...@@ -179,7 +179,7 @@ function ChatThreadRouteView() {...@@ -179,7 +179,7 @@ function ChatThreadRouteView() {
179 if (!shouldUseDiffSheet) {179 if (!shouldUseDiffSheet) {
180 return (180 return (
181 <>181 <>
182 <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground isolate">182 <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground">
183 <ChatView threadId={threadId} />183 <ChatView threadId={threadId} />
184 </SidebarInset>184 </SidebarInset>
185 <DiffPanelInlineSidebar diffOpen={diffOpen} onCloseDiff={closeDiff} onOpenDiff={openDiff} />185 <DiffPanelInlineSidebar diffOpen={diffOpen} onCloseDiff={closeDiff} onOpenDiff={openDiff} />
...@@ -189,7 +189,7 @@ function ChatThreadRouteView() {...@@ -189,7 +189,7 @@ function ChatThreadRouteView() {
189189
190 return (190 return (
191 <>191 <>
192 <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground isolate">192 <SidebarInset className="h-dvh min-h-0 overflow-hidden overscroll-y-none bg-background text-foreground">
193 <ChatView threadId={threadId} />193 <ChatView threadId={threadId} />
194 </SidebarInset>194 </SidebarInset>
195 <DiffPanelSheet diffOpen={diffOpen} onCloseDiff={closeDiff}>195 <DiffPanelSheet diffOpen={diffOpen} onCloseDiff={closeDiff}>