feat: show installed badge and version in agent dropdown menus

This commit is contained in:
Nathan Flurry 2026-01-27 20:34:10 -08:00
parent f452b46b94
commit c498aeba28
4 changed files with 70 additions and 19 deletions

View file

@ -482,6 +482,10 @@
font-size: 12px;
cursor: pointer;
transition: all var(--transition);
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.sidebar-add-option:hover {
@ -489,6 +493,42 @@
color: #fff;
}
.sidebar-add-option:hover .agent-badge {
background: rgba(255, 255, 255, 0.2);
color: #fff;
}
.agent-option-name {
flex: 1;
min-width: 0;
}
.agent-option-badges {
display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
}
.agent-badge {
padding: 2px 6px;
border-radius: 4px;
font-size: 10px;
font-weight: 500;
white-space: nowrap;
transition: all var(--transition);
}
.agent-badge.installed {
background: rgba(48, 209, 88, 0.15);
color: var(--success);
}
.agent-badge.version {
background: var(--border-2);
color: var(--muted);
}
.sidebar-add-status {
padding: 6px 8px;
font-size: 11px;

View file

@ -744,7 +744,6 @@ export default function App() {
}
}, [modesByAgent, agentId]);
const availableAgents = agents.length ? agents.map((agent) => agent.id) : defaultAgents;
const currentAgent = agents.find((agent) => agent.id === agentId);
const activeModes = modesByAgent[agentId] ?? [];
const modesLoading = modesLoadingByAgent[agentId] ?? false;
@ -822,7 +821,7 @@ export default function App() {
onSelectSession={selectSession}
onRefresh={fetchSessions}
onCreateSession={createNewSession}
availableAgents={availableAgents}
agents={agents.length ? agents : defaultAgents.map((id) => ({ id, installed: false, capabilities: {} }) as AgentInfo)}
agentsLoading={agentsLoading}
agentsError={agentsError}
sessionsLoading={sessionsLoading}
@ -840,7 +839,7 @@ export default function App() {
onSendMessage={sendMessage}
onKeyDown={handleKeyDown}
onCreateSession={createNewSession}
availableAgents={availableAgents}
agents={agents.length ? agents : defaultAgents.map((id) => ({ id, installed: false, capabilities: {} }) as AgentInfo)}
agentsLoading={agentsLoading}
agentsError={agentsError}
messagesEndRef={messagesEndRef}

View file

@ -1,6 +1,6 @@
import { Plus, RefreshCw } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import type { SessionInfo } from "sandbox-agent";
import type { AgentInfo, SessionInfo } from "sandbox-agent";
const SessionSidebar = ({
sessions,
@ -8,7 +8,7 @@ const SessionSidebar = ({
onSelectSession,
onRefresh,
onCreateSession,
availableAgents,
agents,
agentsLoading,
agentsError,
sessionsLoading,
@ -19,7 +19,7 @@ const SessionSidebar = ({
onSelectSession: (session: SessionInfo) => void;
onRefresh: () => void;
onCreateSession: (agentId: string) => void;
availableAgents: string[];
agents: AgentInfo[];
agentsLoading: boolean;
agentsError: string | null;
sessionsLoading: boolean;
@ -68,20 +68,26 @@ const SessionSidebar = ({
<div className="sidebar-add-menu">
{agentsLoading && <div className="sidebar-add-status">Loading agents...</div>}
{agentsError && <div className="sidebar-add-status error">{agentsError}</div>}
{!agentsLoading && !agentsError && availableAgents.length === 0 && (
{!agentsLoading && !agentsError && agents.length === 0 && (
<div className="sidebar-add-status">No agents available.</div>
)}
{!agentsLoading && !agentsError &&
availableAgents.map((id) => (
agents.map((agent) => (
<button
key={id}
key={agent.id}
className="sidebar-add-option"
onClick={() => {
onCreateSession(id);
onCreateSession(agent.id);
setShowMenu(false);
}}
>
{agentLabels[id] ?? id}
<span className="agent-option-name">{agentLabels[agent.id] ?? agent.id}</span>
{agent.installed && (
<span className="agent-option-badges">
<span className="agent-badge installed">Installed</span>
{agent.version && <span className="agent-badge version">v{agent.version}</span>}
</span>
)}
</button>
))}
</div>

View file

@ -1,6 +1,6 @@
import { MessageSquare, PauseCircle, PlayCircle, Plus, Terminal } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import type { AgentModeInfo, PermissionEventData, QuestionEventData } from "sandbox-agent";
import type { AgentInfo, AgentModeInfo, PermissionEventData, QuestionEventData } from "sandbox-agent";
import ApprovalsTab from "../debug/ApprovalsTab";
import ChatInput from "./ChatInput";
import ChatMessages from "./ChatMessages";
@ -18,7 +18,7 @@ const ChatPanel = ({
onSendMessage,
onKeyDown,
onCreateSession,
availableAgents,
agents,
agentsLoading,
agentsError,
messagesEndRef,
@ -58,7 +58,7 @@ const ChatPanel = ({
onSendMessage: () => void;
onKeyDown: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;
onCreateSession: (agentId: string) => void;
availableAgents: string[];
agents: AgentInfo[];
agentsLoading: boolean;
agentsError: string | null;
messagesEndRef: React.RefObject<HTMLDivElement>;
@ -188,20 +188,26 @@ const ChatPanel = ({
<div className="empty-state-menu">
{agentsLoading && <div className="sidebar-add-status">Loading agents...</div>}
{agentsError && <div className="sidebar-add-status error">{agentsError}</div>}
{!agentsLoading && !agentsError && availableAgents.length === 0 && (
{!agentsLoading && !agentsError && agents.length === 0 && (
<div className="sidebar-add-status">No agents available.</div>
)}
{!agentsLoading && !agentsError &&
availableAgents.map((id) => (
agents.map((agent) => (
<button
key={id}
key={agent.id}
className="sidebar-add-option"
onClick={() => {
onCreateSession(id);
onCreateSession(agent.id);
setShowAgentMenu(false);
}}
>
{agentLabels[id] ?? id}
<span className="agent-option-name">{agentLabels[agent.id] ?? agent.id}</span>
{agent.installed && (
<span className="agent-option-badges">
<span className="agent-badge installed">Installed</span>
{agent.version && <span className="agent-badge version">v{agent.version}</span>}
</span>
)}
</button>
))}
</div>