diff --git a/core/frontend/src/components/ChatPanel.tsx b/core/frontend/src/components/ChatPanel.tsx index 36c5a612..11fed22c 100644 --- a/core/frontend/src/components/ChatPanel.tsx +++ b/core/frontend/src/components/ChatPanel.tsx @@ -27,6 +27,8 @@ export interface ContextUsageEntry { import MarkdownContent from "@/components/MarkdownContent"; import QuestionWidget from "@/components/QuestionWidget"; import MultiQuestionWidget from "@/components/MultiQuestionWidget"; +import { useColony } from "@/context/ColonyContext"; +import { useQueenProfile } from "@/context/QueenProfileContext"; import ParallelSubagentBubble, { type SubagentGroup, } from "@/components/ParallelSubagentBubble"; @@ -338,6 +340,15 @@ function InlineAskUserBubble({ const color = getColor(msg.agent, msg.role); const thread = msg.thread || activeThread; + const { queenProfiles } = useColony(); + const { openQueenProfile } = useQueenProfile(); + const queenProfileId = isQueen + ? queenProfiles.find((q) => q.name === msg.agent)?.id ?? null + : null; + const handleQueenClick = queenProfileId + ? () => openQueenProfile(queenProfileId) + : undefined; + const handleSingle = (answer: string) => { setState("submitted"); onSend(answer, thread); @@ -357,12 +368,14 @@ function InlineAskUserBubble({ return (
{isQueen ? ( @@ -375,8 +388,9 @@ function InlineAskUserBubble({ >
{msg.agent} @@ -437,6 +451,13 @@ const MessageBubble = memo( const isQueen = msg.role === "queen"; const color = getColor(msg.agent, msg.role); + // Resolve queen profile ID so clicking avatar/name opens the profile panel + const { queenProfiles } = useColony(); + const { openQueenProfile } = useQueenProfile(); + const queenProfileId = isQueen + ? queenProfiles.find((q) => q.name === msg.agent)?.id ?? null + : null; + if (msg.type === "run_divider") { return (
@@ -531,15 +552,21 @@ const MessageBubble = memo( ); } + const handleQueenClick = queenProfileId + ? () => openQueenProfile(queenProfileId) + : undefined; + return (
{isQueen ? ( @@ -552,8 +579,9 @@ const MessageBubble = memo( >
{msg.agent} diff --git a/core/frontend/src/context/QueenProfileContext.tsx b/core/frontend/src/context/QueenProfileContext.tsx new file mode 100644 index 00000000..bacbd5e5 --- /dev/null +++ b/core/frontend/src/context/QueenProfileContext.tsx @@ -0,0 +1,31 @@ +import { createContext, useContext, useCallback, type ReactNode } from "react"; + +interface QueenProfileContextValue { + openQueenProfile: (queenId: string) => void; +} + +const QueenProfileContext = createContext(null); + +export function QueenProfileProvider({ + onOpen, + children, +}: { + onOpen: (queenId: string) => void; + children: ReactNode; +}) { + const openQueenProfile = useCallback( + (queenId: string) => onOpen(queenId), + [onOpen], + ); + return ( + + {children} + + ); +} + +export function useQueenProfile() { + const ctx = useContext(QueenProfileContext); + if (!ctx) throw new Error("useQueenProfile must be used within QueenProfileProvider"); + return ctx; +} diff --git a/core/frontend/src/layouts/AppLayout.tsx b/core/frontend/src/layouts/AppLayout.tsx index dbd79c2d..cb17fa90 100644 --- a/core/frontend/src/layouts/AppLayout.tsx +++ b/core/frontend/src/layouts/AppLayout.tsx @@ -1,10 +1,11 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, useCallback } from "react"; import { Outlet, useLocation } from "react-router-dom"; import Sidebar from "@/components/Sidebar"; import AppHeader from "@/components/AppHeader"; import QueenProfilePanel from "@/components/QueenProfilePanel"; import { ColonyProvider, useColony } from "@/context/ColonyContext"; import { HeaderActionsProvider } from "@/context/HeaderActionsContext"; +import { QueenProfileProvider } from "@/context/QueenProfileContext"; export default function AppLayout() { return ( @@ -27,26 +28,33 @@ function AppLayoutInner() { setOpenQueenId(null); }, [location.pathname]); + const handleOpenQueenProfile = useCallback( + (queenId: string) => setOpenQueenId((prev) => (prev === queenId ? null : queenId)), + [], + ); + return ( -
- -
- -
-
- -
- {openQueenId && ( - c.queenProfileId === openQueenId, - )} - onClose={() => setOpenQueenId(null)} - /> - )} + +
+ +
+ +
+
+ +
+ {openQueenId && ( + c.queenProfileId === openQueenId, + )} + onClose={() => setOpenQueenId(null)} + /> + )} +
-
+ ); }