From 6784a3feec7395a67fee180f2c94573ae6975d77 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 5 Feb 2026 22:40:20 +0700 Subject: [PATCH] Update changes (#15) * Update files * Update files --- .../app/src/components/grouped-agent-list.tsx | 298 ++++++++++++------ 1 file changed, 194 insertions(+), 104 deletions(-) diff --git a/packages/app/src/components/grouped-agent-list.tsx b/packages/app/src/components/grouped-agent-list.tsx index c5f7d4b83..b8c682835 100644 --- a/packages/app/src/components/grouped-agent-list.tsx +++ b/packages/app/src/components/grouped-agent-list.tsx @@ -12,6 +12,7 @@ import { useMemo, useState, useEffect, + useRef, type ReactElement, type MutableRefObject, } from "react"; @@ -24,7 +25,6 @@ import { DraggableList, type DraggableRenderItemInfo, } from "./draggable-list"; -import { formatTimeAgo } from "@/utils/time"; import { parseRepoNameFromRemoteUrl, parseRepoShortNameFromRemoteUrl } from "@/utils/agent-grouping"; import { type AggregatedAgent } from "@/hooks/use-aggregated-agents"; import { useSessionStore } from "@/stores/session-store"; @@ -185,6 +185,164 @@ function SectionHeader({ ); } +interface GroupedAgentRowProps { + agent: AggregatedAgent; + isSelected: boolean; + shortcutNumber: number | null; + onPress: () => void; + onLongPress: () => void; + onArchive: (e: { stopPropagation: () => void }) => void; +} + +function GroupedAgentRow({ + agent, + isSelected, + shortcutNumber, + onPress, + onLongPress, + onArchive, +}: GroupedAgentRowProps) { + const { theme } = useUnistyles(); + const [isHovered, setIsHovered] = useState(false); + const [isArchiveConfirmVisible, setIsArchiveConfirmVisible] = useState(false); + const hoverOutTimeoutRef = useRef | null>(null); + + const clearHoverOutTimeout = useCallback(() => { + if (!hoverOutTimeoutRef.current) { + return; + } + clearTimeout(hoverOutTimeoutRef.current); + hoverOutTimeoutRef.current = null; + }, []); + + useEffect(() => { + return () => clearHoverOutTimeout(); + }, [clearHoverOutTimeout]); + + const handleHoverIn = useCallback(() => { + clearHoverOutTimeout(); + setIsHovered(true); + }, [clearHoverOutTimeout]); + + const handleHoverOut = useCallback(() => { + clearHoverOutTimeout(); + hoverOutTimeoutRef.current = setTimeout(() => { + setIsHovered(false); + setIsArchiveConfirmVisible(false); + }, 50); + }, [clearHoverOutTimeout]); + + const checkoutQuery = useCheckoutStatusCacheOnly({ + serverId: agent.serverId, + cwd: agent.cwd, + }); + const checkout = checkoutQuery.data ?? null; + const activeBranchLabel = checkout?.isGit + ? ((checkout.currentBranch && checkout.currentBranch !== "HEAD" + ? checkout.currentBranch + : null) ?? + checkout.baseRef ?? + "git") + : null; + + const canArchive = agent.status !== "running" && !agent.requiresAttention; + const showArchive = canArchive && shortcutNumber === null && (isHovered || isArchiveConfirmVisible); + + return ( + [ + styles.agentItem, + !isSelected && styles.agentItemUnselected, + isSelected && styles.agentItemSelected, + isHovered && styles.agentItemHovered, + pressed && styles.agentItemPressed, + ]} + onPress={onPress} + onPressIn={() => { + if (Platform.OS !== "web") { + return; + } + handleHoverIn(); + }} + onLongPress={onLongPress} + onHoverIn={handleHoverIn} + onHoverOut={handleHoverOut} + testID={`agent-row-${agent.serverId}-${agent.id}`} + > + + + + + {agent.title || "New agent"} + + {shortcutNumber !== null ? ( + + + {shortcutNumber} + + + ) : showArchive ? ( + { + e.stopPropagation(); + if (!isArchiveConfirmVisible) { + setIsArchiveConfirmVisible(true); + return; + } + onArchive(e); + setIsArchiveConfirmVisible(false); + }} + testID={ + isArchiveConfirmVisible + ? `agent-archive-confirm-${agent.serverId}-${agent.id}` + : `agent-archive-${agent.serverId}-${agent.id}` + } + > + {({ hovered: archiveHovered }) => + isArchiveConfirmVisible ? ( + + Confirm + + ) : ( + + ) + } + + ) : activeBranchLabel ? ( + + + {activeBranchLabel} + + + ) : null} + + + + ); +} + export function GroupedAgentList({ agents, isRefreshing = false, @@ -337,107 +495,6 @@ export function GroupedAgentList({ [] ); - const AgentListRow = useCallback( - ({ agent }: { agent: AggregatedAgent }) => { - const [isHovered, setIsHovered] = useState(false); - const timeAgo = formatTimeAgo(agent.lastActivityAt); - const agentKey = `${agent.serverId}:${agent.id}`; - const isSelected = selectedAgentId === agentKey; - const isRunning = agent.status === "running"; - const shortcutNumber = - showShortcutBadges ? (shortcutIndexByAgentKey.get(agentKey) ?? null) : null; - - const checkoutQuery = useCheckoutStatusCacheOnly({ - serverId: agent.serverId, - cwd: agent.cwd, - }); - const checkout = checkoutQuery.data ?? null; - const activeBranchLabel = checkout?.isGit - ? ((checkout.currentBranch && checkout.currentBranch !== "HEAD" - ? checkout.currentBranch - : null) ?? - checkout.baseRef ?? - "git") - : null; - - const canArchive = !isRunning && !agent.requiresAttention; - - return ( - [ - styles.agentItem, - !isSelected && styles.agentItemUnselected, - isSelected && styles.agentItemSelected, - isHovered && styles.agentItemHovered, - pressed && styles.agentItemPressed, - ]} - onPress={() => handleAgentPress(agent.serverId, agent.id)} - onLongPress={() => handleAgentLongPress(agent)} - onHoverIn={() => setIsHovered(true)} - onHoverOut={() => setIsHovered(false)} - testID={`agent-row-${agent.serverId}-${agent.id}`} - > - - - - - {agent.title || "New agent"} - - {shortcutNumber !== null ? ( - - - {shortcutNumber} - - - ) : isHovered && canArchive ? ( - handleArchiveAgent(e, agent)} - onHoverIn={() => setIsHovered(true)} - onHoverOut={() => setIsHovered(true)} - testID={`agent-archive-${agent.serverId}-${agent.id}`} - > - {({ hovered: archiveHovered }) => ( - - )} - - ) : activeBranchLabel ? ( - - - {activeBranchLabel} - - - ) : null} - - - - ); - }, - [ - handleAgentLongPress, - handleAgentPress, - handleArchiveAgent, - selectedAgentId, - showShortcutBadges, - shortcutIndexByAgentKey, - theme.colors.foreground, - theme.colors.foregroundMuted, - ] - ); - const renderSection = useCallback( ({ item: section, drag, isActive }: DraggableRenderItemInfo) => { const isCollapsed = collapsedProjectKeys.has(section.projectKey); @@ -454,12 +511,34 @@ export function GroupedAgentList({ /> {!isCollapsed && section.agents.map((agent) => ( - + handleAgentPress(agent.serverId, agent.id)} + onLongPress={() => handleAgentLongPress(agent)} + onArchive={(e) => handleArchiveAgent(e, agent)} + /> ))} ); }, - [AgentListRow, collapsedProjectKeys, handleCreateAgentInProject, toggleProjectCollapsed] + [ + collapsedProjectKeys, + handleAgentLongPress, + handleAgentPress, + handleArchiveAgent, + handleCreateAgentInProject, + selectedAgentId, + showShortcutBadges, + shortcutIndexByAgentKey, + toggleProjectCollapsed, + ] ); const keyExtractor = useCallback( @@ -675,6 +754,17 @@ const styles = StyleSheet.create((theme) => ({ color: theme.colors.foregroundMuted, lineHeight: 12, }, + archiveConfirmBadge: { + minWidth: 76, + maxWidth: 9999, + flexShrink: 0, + }, + archiveConfirmText: { + color: theme.colors.foreground, + }, + archiveConfirmTextHovered: { + opacity: 0.9, + }, agentTitleHighlighted: { color: theme.colors.foreground, opacity: 1,