From d92ab08416883702da12db64c0285a794701d5a8 Mon Sep 17 00:00:00 2001 From: iliya Date: Sat, 21 Mar 2026 12:31:51 +0200 Subject: [PATCH] feat: show tool approval in Awaiting Replies + Allow All button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PendingRepliesBlock: show "user — awaiting approval" entry when pendingApprovals exist, with amber pulse dot and ShieldQuestion icon - ToolApprovalSheet: add grey "Allow all" button (separated by divider) right of Allow/Deny — enables autoAllowAll setting instantly --- .../components/team/ToolApprovalSheet.tsx | 27 ++++++ .../team/activity/PendingRepliesBlock.tsx | 93 +++++++++++++++---- 2 files changed, 102 insertions(+), 18 deletions(-) diff --git a/src/renderer/components/team/ToolApprovalSheet.tsx b/src/renderer/components/team/ToolApprovalSheet.tsx index 6f986f5a..0d3ff62c 100644 --- a/src/renderer/components/team/ToolApprovalSheet.tsx +++ b/src/renderer/components/team/ToolApprovalSheet.tsx @@ -104,6 +104,7 @@ const RESPOND_TIMEOUT_MS = 10_000; export const ToolApprovalSheet: React.FC = () => { const pendingApprovals = useStore((s) => s.pendingApprovals); const respondToToolApproval = useStore((s) => s.respondToToolApproval); + const updateToolApprovalSettings = useStore((s) => s.updateToolApprovalSettings); const teams = useStore((s) => s.teams); const selectedTeamName = useStore((s) => s.selectedTeamName); const { isLight } = useTheme(); @@ -281,6 +282,32 @@ export const ToolApprovalSheet: React.FC = () => { > Deny + +
+ +
{pendingApprovals.length > 1 && ( diff --git a/src/renderer/components/team/activity/PendingRepliesBlock.tsx b/src/renderer/components/team/activity/PendingRepliesBlock.tsx index 1f887946..e7946534 100644 --- a/src/renderer/components/team/activity/PendingRepliesBlock.tsx +++ b/src/renderer/components/team/activity/PendingRepliesBlock.tsx @@ -1,6 +1,7 @@ import { CARD_BG, CARD_BORDER_STYLE, CARD_ICON_MUTED } from '@renderer/constants/cssVariables'; import { getTeamColorSet, getThemedBadge } from '@renderer/constants/teamColors'; import { useTheme } from '@renderer/hooks/useTheme'; +import { useStore } from '@renderer/store'; import { formatAgentRole } from '@renderer/utils/formatAgentRole'; import { agentAvatarUrl, @@ -9,7 +10,7 @@ import { } from '@renderer/utils/memberHelpers'; import { nameColorSet } from '@renderer/utils/projectColor'; import { formatDistanceToNowStrict } from 'date-fns'; -import { Users } from 'lucide-react'; +import { ShieldQuestion, Users } from 'lucide-react'; import type { ResolvedTeamMember } from '@shared/types'; @@ -32,6 +33,7 @@ export const PendingRepliesBlock = ({ onMemberClick, }: PendingRepliesBlockProps): React.JSX.Element | null => { const { isLight } = useTheme(); + const pendingApprovals = useStore((s) => s.pendingApprovals); const colorMap = buildMemberColorMap(members); const memberPending = Object.entries(pendingRepliesByMember) .map(([name, sentAtMs]) => ({ @@ -49,7 +51,17 @@ export const PendingRepliesBlock = ({ teamName: entry.teamName, sentAtMs: entry.sentAtMs, })); - const pending = [...memberPending, ...teamPending].sort((a, b) => b.sentAtMs - a.sentAtMs); + + // Tool approvals awaiting user response + const userPending = pendingApprovals.map((a) => ({ + kind: 'user' as const, + toolName: a.toolName, + sentAtMs: new Date(a.receivedAt).getTime(), + })); + + const pending = [...memberPending, ...teamPending, ...userPending].sort( + (a, b) => b.sentAtMs - a.sentAtMs + ); if (pending.length === 0) return null; @@ -137,45 +149,90 @@ export const PendingRepliesBlock = ({ ); } - const colors = nameColorSet(entry.teamName, isLight); + if (entry.kind === 'team') { + const colors = nameColorSet(entry.teamName, isLight); + return ( +
+
+ + + + + + + + + {entry.teamName} + + + external team + + + awaiting reply + + + {since} + +
+
+ ); + } + + // User tool approval pending return (
- + - - + + - {entry.teamName} - - - external team + user - awaiting reply + awaiting approval {since}