Spaces:
Running
Running
File size: 5,542 Bytes
dd87944 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | import React, { useState } from "react";
import { Activity, FolderTree, Bot, X } from "lucide-react";
import FileExplorer from "./FileExplorer";
import AgentSettingsPanel from "./AgentSettingsPanel";
import BrowserPanel from "./BrowserPanel";
const TABS = [
{ id: "activity", label: "Activité", icon: Activity },
{ id: "files", label: "Fichiers", icon: FolderTree },
{ id: "agent", label: "Agent", icon: Bot },
];
export default function RightPanel({
tools,
agentOnline,
agentToolsOnline,
onRefreshStatus,
onClose,
filePreview = null,
activeTab,
onTabChange,
browserFrames = [],
reflectNotes = [],
onBrowserFrameUpdate,
mobileSheet = false,
}) {
const [fallbackTab, setFallbackTab] = useState("activity");
const tab = activeTab ?? fallbackTab;
const selectTab = (id) => {
if (activeTab == null) setFallbackTab(id);
onTabChange?.(id);
};
return (
<aside
data-testid="right-panel"
className={
mobileSheet
? "flex w-full min-w-0 flex-1 flex-col emo-panel-flat emo-right-panel-sheet overflow-hidden"
: "hidden md:flex emo-right-panel flex-shrink-0 h-full flex-col emo-panel-flat"
}
style={{
borderLeft: mobileSheet ? "none" : "1px solid var(--emo-border)",
background: "var(--emo-surface)",
}}
>
<div className="emo-panel-tabs flex-shrink-0">
<div className="flex items-center gap-1 flex-1 min-w-0 overflow-x-auto scrollbar-thin">
{TABS.map((t) => {
const Icon = t.icon;
const active = t.id === tab;
return (
<button
key={t.id}
type="button"
data-testid={`right-tab-${t.id}`}
onClick={() => selectTab(t.id)}
className="emo-panel-tab flex-shrink-0"
data-active={active ? "true" : "false"}
aria-selected={active}
>
<Icon size={13} style={{ color: active ? "var(--mode-color)" : "currentColor" }} />
{t.label}
</button>
);
})}
</div>
{onClose && (
<button type="button" onClick={onClose} className="emo-icon-btn ml-1 flex-shrink-0" data-testid="right-panel-close">
<X size={14} />
</button>
)}
</div>
<div className="emo-panel-tab-stack">
<div
className="emo-panel-tab-pane"
data-active={tab === "activity" ? "true" : "false"}
aria-hidden={tab !== "activity"}
>
<ActivityTab
tools={tools}
agentOnline={agentOnline}
agentToolsOnline={agentToolsOnline}
browserFrames={browserFrames}
reflectNotes={reflectNotes}
onBrowserFrameUpdate={onBrowserFrameUpdate}
/>
</div>
<div
className="emo-panel-tab-pane"
data-active={tab === "files" ? "true" : "false"}
aria-hidden={tab !== "files"}
>
<FileExplorer agentOnline={agentToolsOnline} externalPreview={filePreview} />
</div>
<div
className="emo-panel-tab-pane"
data-active={tab === "agent" ? "true" : "false"}
aria-hidden={tab !== "agent"}
>
<div className="p-4 overflow-y-auto h-full scrollbar-thin">
<AgentSettingsPanel agentOnline={agentOnline} onRefreshStatus={onRefreshStatus} />
</div>
</div>
</div>
</aside>
);
}
const ActivityTab = ({ tools, agentOnline, agentToolsOnline, browserFrames, reflectNotes, onBrowserFrameUpdate }) => (
<div className="h-full flex flex-col overflow-hidden" data-testid="activity-tab">
<div
className="flex-shrink-0 flex items-center gap-2 text-[10px] uppercase tracking-wide font-medium text-muted-em px-4 py-2.5"
style={{ borderBottom: "1px solid var(--emo-border)", background: "var(--emo-bg-subtle)" }}
>
<div
className={`w-2 h-2 rounded-full ${agentOnline ? "emo-status-dot-online" : "emo-status-dot-offline"}`}
/>
Desktop {agentOnline ? "connecté" : "hors ligne"}
{agentToolsOnline ? (
<span className="normal-case tracking-normal opacity-70 font-normal">· outils actifs</span>
) : null}
{tools.length > 0 && (
<span className="normal-case tracking-normal opacity-70 font-normal">
· {tools.length} action{tools.length !== 1 ? "s" : ""}
</span>
)}
</div>
<div className="flex-1 min-h-0">
<BrowserPanel frames={browserFrames} reflectNotes={reflectNotes} onFrameUpdate={onBrowserFrameUpdate} />
</div>
{tools.length > 0 && (
<div
className="flex-shrink-0 max-h-32 overflow-y-auto scrollbar-thin p-2.5 space-y-1.5"
style={{ borderTop: "1px solid var(--emo-border)", background: "var(--emo-bg-subtle)" }}
>
{tools.slice(-8).map((t) => (
<div
key={t.id}
className="text-xs px-3 py-2 rounded-xl flex items-center justify-between"
style={{ background: "var(--emo-surface)", border: "1px solid var(--emo-border)" }}
>
<span className="font-code text-[11px] font-medium" style={{ color: "var(--mode-color)" }}>{t.tool}</span>
<span className="text-muted-em text-[10px]">
{t.state === "executing" ? "en cours…" : t.state === "error" ? "erreur" : "ok"}
</span>
</div>
))}
</div>
)}
</div>
);
|