From ab48eafe615928adbb69602a1a5165bed747d9d7 Mon Sep 17 00:00:00 2001 From: Jiang Bohan Date: Wed, 1 Apr 2026 15:49:01 +0800 Subject: [PATCH] feat(agents): add avatar upload to agent settings page Add avatar upload UI to the agent SettingsTab, matching the existing member avatar upload pattern. Also update the agent list item and detail header to display the uploaded avatar image. --- apps/web/app/(dashboard)/agents/page.tsx | 77 ++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 5 deletions(-) diff --git a/apps/web/app/(dashboard)/agents/page.tsx b/apps/web/app/(dashboard)/agents/page.tsx index a6e8c092..e87934a8 100644 --- a/apps/web/app/(dashboard)/agents/page.tsx +++ b/apps/web/app/(dashboard)/agents/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; import { useDefaultLayout } from "react-resizable-panels"; import { Bot, @@ -28,6 +28,7 @@ import { Globe, Lock, Settings, + Camera, } from "lucide-react"; import type { Agent, @@ -74,6 +75,7 @@ import { useAuthStore } from "@/features/auth"; import { useWorkspaceStore } from "@/features/workspace"; import { useRuntimeStore } from "@/features/runtimes"; import { useIssueStore } from "@/features/issues"; +import { useFileUpload } from "@/shared/hooks/use-file-upload"; // --------------------------------------------------------------------------- @@ -341,8 +343,12 @@ function AgentListItem({ isSelected ? "bg-accent" : "hover:bg-accent/50" }`} > -
- {getInitials(agent.name)} +
+ {agent.avatar_url ? ( + {agent.name} + ) : ( + getInitials(agent.name) + )}
@@ -1173,6 +1179,22 @@ function SettingsTab({ const [visibility, setVisibility] = useState(agent.visibility); const [maxTasks, setMaxTasks] = useState(agent.max_concurrent_tasks); const [saving, setSaving] = useState(false); + const { upload, uploading } = useFileUpload(); + const fileInputRef = useRef(null); + + const handleAvatarUpload = async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + e.target.value = ""; + try { + const result = await upload(file); + if (!result) return; + await onSave({ avatar_url: result.link }); + toast.success("Avatar updated"); + } catch (err) { + toast.error(err instanceof Error ? err.message : "Failed to upload avatar"); + } + }; const dirty = name !== agent.name || @@ -1200,6 +1222,47 @@ function SettingsTab({ return (
+
+ +
+ + +
+ Click to upload avatar +
+
+
+
{/* Header */}
-
- {getInitials(agent.name)} +
+ {agent.avatar_url ? ( + {agent.name} + ) : ( + getInitials(agent.name) + )}