diff --git a/src/browser/components/GitStatusIndicator.tsx b/src/browser/components/GitStatusIndicator.tsx index 88960d4897..942c45c592 100644 --- a/src/browser/components/GitStatusIndicator.tsx +++ b/src/browser/components/GitStatusIndicator.tsx @@ -7,6 +7,8 @@ interface GitStatusIndicatorProps { gitStatus: GitStatus | null; workspaceId: string; tooltipPosition?: "right" | "bottom"; + /** When true, shows blue pulsing styling to indicate agent is working */ + isWorking?: boolean; } /** @@ -18,6 +20,7 @@ export const GitStatusIndicator: React.FC = ({ gitStatus, workspaceId, tooltipPosition = "right", + isWorking = false, }) => { const [showTooltip, setShowTooltip] = useState(false); const [tooltipCoords, setTooltipCoords] = useState<{ top: number; left: number }>({ @@ -118,6 +121,7 @@ export const GitStatusIndicator: React.FC = ({ onTooltipMouseEnter={handleTooltipMouseEnter} onTooltipMouseLeave={handleTooltipMouseLeave} onContainerRef={handleContainerRef} + isWorking={isWorking} /> ); }; diff --git a/src/browser/components/GitStatusIndicatorView.tsx b/src/browser/components/GitStatusIndicatorView.tsx index e1b72009b1..5e96c844af 100644 --- a/src/browser/components/GitStatusIndicatorView.tsx +++ b/src/browser/components/GitStatusIndicatorView.tsx @@ -35,6 +35,8 @@ export interface GitStatusIndicatorViewProps { onTooltipMouseEnter: () => void; onTooltipMouseLeave: () => void; onContainerRef: (el: HTMLSpanElement | null) => void; + /** When true, shows blue pulsing styling to indicate agent is working */ + isWorking?: boolean; } /** @@ -57,6 +59,7 @@ export const GitStatusIndicatorView: React.FC = ({ onTooltipMouseEnter, onTooltipMouseLeave, onContainerRef, + isWorking = false, }) => { // Handle null gitStatus (loading state) if (!gitStatus) { @@ -202,13 +205,20 @@ export const GitStatusIndicatorView: React.FC = ({ ); + // Dynamic color based on working state + const statusColor = isWorking ? "text-blue-400 animate-pulse" : "text-muted"; + const dirtyColor = isWorking ? "text-blue-400" : "text-git-dirty"; + return ( <> {gitStatus.ahead > 0 && ( ↑{gitStatus.ahead} @@ -217,7 +227,7 @@ export const GitStatusIndicatorView: React.FC = ({ ↓{gitStatus.behind} )} {gitStatus.dirty && ( - * + * )} diff --git a/src/browser/components/RuntimeBadge.tsx b/src/browser/components/RuntimeBadge.tsx index b5f175bda2..93244ac994 100644 --- a/src/browser/components/RuntimeBadge.tsx +++ b/src/browser/components/RuntimeBadge.tsx @@ -8,6 +8,8 @@ import { TooltipWrapper, Tooltip } from "./Tooltip"; interface RuntimeBadgeProps { runtimeConfig?: RuntimeConfig; className?: string; + /** When true, shows blue pulsing styling to indicate agent is working */ + isWorking?: boolean; } /** Server rack icon for SSH runtime */ @@ -56,8 +58,8 @@ function WorktreeIcon() { ); } -/** Folder icon for local project-dir runtime (reserved for future use) */ -function _LocalIcon() { +/** Folder icon for local project-dir runtime */ +function LocalIcon() { return ( @@ -109,8 +119,8 @@ export function RuntimeBadge({ runtimeConfig, className }: RuntimeBadgeProps) { @@ -121,10 +131,22 @@ export function RuntimeBadge({ runtimeConfig, className }: RuntimeBadgeProps) { ); } - // Local project-dir runtime: don't show badge (it's the simplest/default) - // Could optionally show LocalIcon if we want visibility + // Local project-dir runtime: show folder icon if (isLocalProjectRuntime(runtimeConfig)) { - return null; // No badge for simple local runtimes + return ( + + + + + Local: project directory + + ); } return null; diff --git a/src/browser/components/WorkspaceHeader.tsx b/src/browser/components/WorkspaceHeader.tsx index 1f50523e75..c6be5716f5 100644 --- a/src/browser/components/WorkspaceHeader.tsx +++ b/src/browser/components/WorkspaceHeader.tsx @@ -4,8 +4,8 @@ import { RuntimeBadge } from "./RuntimeBadge"; import { TooltipWrapper, Tooltip } from "./Tooltip"; import { formatKeybind, KEYBINDS } from "@/browser/utils/ui/keybinds"; import { useGitStatus } from "@/browser/stores/GitStatusStore"; +import { useWorkspaceSidebarState } from "@/browser/stores/WorkspaceStore"; import type { RuntimeConfig } from "@/common/types/runtime"; -import { WorkspaceStatusDot } from "./WorkspaceStatusDot"; import { useTutorial } from "@/browser/contexts/TutorialContext"; interface WorkspaceHeaderProps { @@ -24,6 +24,7 @@ export const WorkspaceHeader: React.FC = ({ runtimeConfig, }) => { const gitStatus = useGitStatus(workspaceId); + const { canInterrupt } = useWorkspaceSidebarState(workspaceId); const handleOpenTerminal = useCallback(() => { void window.api.terminal.openWindow(workspaceId); }, [workspaceId]); @@ -46,13 +47,13 @@ export const WorkspaceHeader: React.FC = ({ return (
- + - {projectName} / {branch} diff --git a/src/browser/components/WorkspaceListItem.tsx b/src/browser/components/WorkspaceListItem.tsx index 8a702e00bd..e3c2b32e17 100644 --- a/src/browser/components/WorkspaceListItem.tsx +++ b/src/browser/components/WorkspaceListItem.tsx @@ -3,11 +3,10 @@ import { cn } from "@/common/lib/utils"; import { useGitStatus } from "@/browser/stores/GitStatusStore"; import { useWorkspaceSidebarState } from "@/browser/stores/WorkspaceStore"; import type { FrontendWorkspaceMetadata } from "@/common/types/workspace"; -import React, { useCallback, useState } from "react"; +import React, { useState } from "react"; import { GitStatusIndicator } from "./GitStatusIndicator"; import { RuntimeBadge } from "./RuntimeBadge"; import { Tooltip, TooltipWrapper } from "./Tooltip"; -import { WorkspaceStatusDot } from "./WorkspaceStatusDot"; import { WorkspaceStatusIndicator } from "./WorkspaceStatusIndicator"; import { Shimmer } from "./ai-elements/shimmer"; @@ -24,11 +23,13 @@ export interface WorkspaceListItemProps { projectName: string; isSelected: boolean; isDeleting?: boolean; - lastReadTimestamp: number; + /** @deprecated No longer used since status dot was removed, kept for API compatibility */ + lastReadTimestamp?: number; // Event handlers onSelectWorkspace: (selection: WorkspaceSelection) => void; onRemoveWorkspace: (workspaceId: string, button: HTMLElement) => Promise; - onToggleUnread: (workspaceId: string) => void; + /** @deprecated No longer used since status dot was removed, kept for API compatibility */ + onToggleUnread?: (workspaceId: string) => void; } const WorkspaceListItemInner: React.FC = ({ @@ -37,10 +38,10 @@ const WorkspaceListItemInner: React.FC = ({ projectName, isSelected, isDeleting, - lastReadTimestamp, + lastReadTimestamp: _lastReadTimestamp, onSelectWorkspace, onRemoveWorkspace, - onToggleUnread, + onToggleUnread: _onToggleUnread, }) => { // Destructure metadata for convenience const { id: workspaceId, name: workspaceName, namedWorkspacePath } = metadata; @@ -93,12 +94,6 @@ const WorkspaceListItemInner: React.FC = ({ } }; - // Memoize toggle unread handler to prevent AgentStatusIndicator re-renders - const handleToggleUnread = useCallback( - () => onToggleUnread(workspaceId), - [onToggleUnread, workspaceId] - ); - const { canInterrupt } = useWorkspaceSidebarState(workspaceId); return ( @@ -135,16 +130,9 @@ const WorkspaceListItemInner: React.FC = ({ data-workspace-path={namedWorkspacePath} data-workspace-id={workspaceId} > -
- -
- + {isEditing ? ( = ({ gitStatus={gitStatus} workspaceId={workspaceId} tooltipPosition="right" + isWorking={canInterrupt} />