| ... | @@ -15,6 +15,7 @@ import { newCommandId, newProjectId, newThreadId } from "../lib/utils"; | ... | @@ -15,6 +15,7 @@ import { newCommandId, newProjectId, newThreadId } from "../lib/utils"; |
| 15 | import { useStore } from "../store"; | 15 | import { useStore } from "../store"; |
| 16 | import { isChatNewLocalShortcut, isChatNewShortcut } from "../keybindings"; | 16 | import { isChatNewLocalShortcut, isChatNewShortcut } from "../keybindings"; |
| 17 | import { type Thread } from "../types"; | 17 | import { type Thread } from "../types"; |
| | 18 | import { derivePendingApprovals } from "../session-logic"; |
| 18 | import { gitRemoveWorktreeMutationOptions } from "../lib/gitReactQuery"; | 19 | import { gitRemoveWorktreeMutationOptions } from "../lib/gitReactQuery"; |
| 19 | import { serverConfigQueryOptions } from "../lib/serverReactQuery"; | 20 | import { serverConfigQueryOptions } from "../lib/serverReactQuery"; |
| 20 | import { readNativeApi } from "../nativeApi"; | 21 | import { readNativeApi } from "../nativeApi"; |
| ... | @@ -50,7 +51,7 @@ function formatRelativeTime(iso: string): string { | ... | @@ -50,7 +51,7 @@ function formatRelativeTime(iso: string): string { |
| 50 | } | 51 | } |
| 51 | | 52 | |
| 52 | interface ThreadStatusPill { | 53 | interface 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 { |
| 76 | function threadStatusPill(thread: Thread, hasPendingApprovals: boolean): ThreadStatusPill | null { | 77 | function 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]); |
| 162 | | 169 | |
| 163 | const handleNewThread = useCallback( | 170 | const handleNewThread = useCallback( |
| 164 | ( | 171 | ( |