@elizaos/client 1.5.5-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +350 -0
- package/dist/assets/empty-module-CLMscLYw.js +1 -0
- package/dist/assets/main-BBZ_3lkn.css +5999 -0
- package/dist/assets/main-C5zNUkXH.js +7 -0
- package/dist/assets/main-Dz64ENQg.js +614 -0
- package/dist/assets/react-vendor-DM5m98rr.js +545 -0
- package/dist/assets/ui-vendor-BQCqNqg0.js +1 -0
- package/dist/elizaos-avatar.png +0 -0
- package/dist/elizaos-icon.png +0 -0
- package/dist/elizaos-logo-light.png +0 -0
- package/dist/elizaos.webp +0 -0
- package/dist/favicon.ico +0 -0
- package/dist/images/agents/agent1.png +0 -0
- package/dist/images/agents/agent2.png +0 -0
- package/dist/images/agents/agent3.png +0 -0
- package/dist/images/agents/agent4.png +0 -0
- package/dist/images/agents/agent5.png +0 -0
- package/dist/index.html +14 -0
- package/index.html +24 -0
- package/package.json +159 -0
- package/postcss.config.js +3 -0
- package/public/elizaos-avatar.png +0 -0
- package/public/elizaos-icon.png +0 -0
- package/public/elizaos-logo-light.png +0 -0
- package/public/elizaos.webp +0 -0
- package/public/favicon.ico +0 -0
- package/public/images/agents/agent1.png +0 -0
- package/public/images/agents/agent2.png +0 -0
- package/public/images/agents/agent3.png +0 -0
- package/public/images/agents/agent4.png +0 -0
- package/public/images/agents/agent5.png +0 -0
- package/src/App.tsx +222 -0
- package/src/components/AgentDetailsPanel.tsx +147 -0
- package/src/components/ChatInputArea.tsx +196 -0
- package/src/components/ChatMessageListComponent.tsx +139 -0
- package/src/components/actionTool.tsx +186 -0
- package/src/components/add-agent-card.tsx +77 -0
- package/src/components/agent-action-viewer.tsx +816 -0
- package/src/components/agent-avatar-stack.tsx +121 -0
- package/src/components/agent-card.cy.tsx +259 -0
- package/src/components/agent-card.tsx +177 -0
- package/src/components/agent-creator.tsx +142 -0
- package/src/components/agent-log-viewer.tsx +645 -0
- package/src/components/agent-memory-edit-overlay.tsx +461 -0
- package/src/components/agent-memory-viewer.tsx +504 -0
- package/src/components/agent-settings.tsx +270 -0
- package/src/components/agent-sidebar.tsx +178 -0
- package/src/components/api-key-dialog.tsx +113 -0
- package/src/components/app-sidebar.tsx +685 -0
- package/src/components/array-input.tsx +116 -0
- package/src/components/audio-recorder.tsx +292 -0
- package/src/components/avatar-panel.tsx +141 -0
- package/src/components/character-form.tsx +1138 -0
- package/src/components/chat.tsx +1813 -0
- package/src/components/combobox.tsx +187 -0
- package/src/components/confirmation-dialog.tsx +59 -0
- package/src/components/connection-error-banner.tsx +101 -0
- package/src/components/connection-status.cy.tsx +73 -0
- package/src/components/connection-status.tsx +155 -0
- package/src/components/copy-button.tsx +35 -0
- package/src/components/delete-button.tsx +24 -0
- package/src/components/env-settings.tsx +261 -0
- package/src/components/group-card.tsx +160 -0
- package/src/components/group-panel.tsx +543 -0
- package/src/components/input-copy.tsx +21 -0
- package/src/components/logs-page.tsx +41 -0
- package/src/components/media-content.tsx +385 -0
- package/src/components/memory-graph.tsx +170 -0
- package/src/components/missing-secrets-dialog.tsx +72 -0
- package/src/components/onboarding-tour.tsx +247 -0
- package/src/components/page-title.tsx +8 -0
- package/src/components/plugins-panel.tsx +383 -0
- package/src/components/profile-card.tsx +66 -0
- package/src/components/profile-overlay.tsx +283 -0
- package/src/components/retry-button.tsx +28 -0
- package/src/components/secret-panel.tsx +1505 -0
- package/src/components/server-management.tsx +264 -0
- package/src/components/split-button.tsx +148 -0
- package/src/components/stop-agent-button.tsx +99 -0
- package/src/components/ui/alert-dialog.cy.tsx +333 -0
- package/src/components/ui/alert-dialog.tsx +115 -0
- package/src/components/ui/alert.tsx +49 -0
- package/src/components/ui/avatar.cy.tsx +180 -0
- package/src/components/ui/avatar.tsx +57 -0
- package/src/components/ui/badge.cy.tsx +146 -0
- package/src/components/ui/badge.tsx +43 -0
- package/src/components/ui/button.cy.tsx +177 -0
- package/src/components/ui/button.tsx +56 -0
- package/src/components/ui/card.cy.tsx +160 -0
- package/src/components/ui/card.tsx +73 -0
- package/src/components/ui/chat/animated-markdown.tsx +59 -0
- package/src/components/ui/chat/chat-bubble.tsx +178 -0
- package/src/components/ui/chat/chat-container.tsx +51 -0
- package/src/components/ui/chat/chat-input.cy.tsx +169 -0
- package/src/components/ui/chat/chat-input.tsx +47 -0
- package/src/components/ui/chat/chat-message-list.tsx +61 -0
- package/src/components/ui/chat/chat-tts-button.tsx +199 -0
- package/src/components/ui/chat/code-block.tsx +79 -0
- package/src/components/ui/chat/expandable-chat.tsx +131 -0
- package/src/components/ui/chat/hooks/useAutoScroll.ts +86 -0
- package/src/components/ui/chat/markdown.tsx +209 -0
- package/src/components/ui/chat/message-loading.tsx +48 -0
- package/src/components/ui/checkbox.cy.tsx +170 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/collapsible.cy.tsx +283 -0
- package/src/components/ui/collapsible.tsx +9 -0
- package/src/components/ui/command.cy.tsx +313 -0
- package/src/components/ui/command.tsx +143 -0
- package/src/components/ui/dialog.cy.tsx +279 -0
- package/src/components/ui/dialog.tsx +104 -0
- package/src/components/ui/dropdown-menu.cy.tsx +273 -0
- package/src/components/ui/dropdown-menu.tsx +281 -0
- package/src/components/ui/input.cy.tsx +82 -0
- package/src/components/ui/input.tsx +27 -0
- package/src/components/ui/label.cy.tsx +157 -0
- package/src/components/ui/label.tsx +19 -0
- package/src/components/ui/resizable.tsx +42 -0
- package/src/components/ui/scroll-area.cy.tsx +242 -0
- package/src/components/ui/scroll-area.tsx +46 -0
- package/src/components/ui/select.cy.tsx +277 -0
- package/src/components/ui/select.tsx +155 -0
- package/src/components/ui/separator.cy.tsx +145 -0
- package/src/components/ui/separator.tsx +29 -0
- package/src/components/ui/sheet.cy.tsx +324 -0
- package/src/components/ui/sheet.tsx +119 -0
- package/src/components/ui/sidebar.tsx +734 -0
- package/src/components/ui/skeleton.cy.tsx +149 -0
- package/src/components/ui/skeleton.tsx +17 -0
- package/src/components/ui/split-button.cy.tsx +274 -0
- package/src/components/ui/split-button.tsx +112 -0
- package/src/components/ui/switch.tsx +28 -0
- package/src/components/ui/tabs.cy.tsx +271 -0
- package/src/components/ui/tabs.tsx +53 -0
- package/src/components/ui/textarea.cy.tsx +136 -0
- package/src/components/ui/textarea.tsx +26 -0
- package/src/components/ui/toast.cy.tsx +209 -0
- package/src/components/ui/toast.tsx +126 -0
- package/src/components/ui/toaster.tsx +29 -0
- package/src/components/ui/tooltip.cy.tsx +244 -0
- package/src/components/ui/tooltip.tsx +30 -0
- package/src/config/agent-templates.ts +349 -0
- package/src/config/voice-models.ts +181 -0
- package/src/constants.ts +23 -0
- package/src/context/AuthContext.tsx +44 -0
- package/src/context/ConnectionContext.tsx +194 -0
- package/src/entry.tsx +9 -0
- package/src/hooks/__tests__/use-agent-tab-state.test.ts +137 -0
- package/src/hooks/__tests__/use-agent-update.test.tsx +250 -0
- package/src/hooks/__tests__/use-character-convert.test.ts +102 -0
- package/src/hooks/__tests__/use-panel-width-state.test.ts +243 -0
- package/src/hooks/__tests__/use-sidebar-state.test.ts +117 -0
- package/src/hooks/use-agent-management.ts +130 -0
- package/src/hooks/use-agent-tab-state.ts +74 -0
- package/src/hooks/use-agent-update.ts +469 -0
- package/src/hooks/use-character-convert.ts +138 -0
- package/src/hooks/use-confirmation.ts +55 -0
- package/src/hooks/use-delete-agent.ts +123 -0
- package/src/hooks/use-dm-channels.ts +198 -0
- package/src/hooks/use-elevenlabs-voices.ts +83 -0
- package/src/hooks/use-file-upload.ts +224 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/hooks/use-onboarding.tsx +49 -0
- package/src/hooks/use-panel-width-state.ts +147 -0
- package/src/hooks/use-partial-update.ts +288 -0
- package/src/hooks/use-plugin-details.ts +462 -0
- package/src/hooks/use-plugins.ts +119 -0
- package/src/hooks/use-query-hooks.ts +1263 -0
- package/src/hooks/use-server-agents.ts +62 -0
- package/src/hooks/use-server-version.tsx +47 -0
- package/src/hooks/use-sidebar-state.ts +50 -0
- package/src/hooks/use-socket-chat.ts +264 -0
- package/src/hooks/use-toast.ts +260 -0
- package/src/hooks/use-version.tsx +64 -0
- package/src/index.css +146 -0
- package/src/lib/api-client-config.ts +53 -0
- package/src/lib/api-type-mappers.ts +196 -0
- package/src/lib/export-utils.ts +123 -0
- package/src/lib/logger.ts +19 -0
- package/src/lib/media-utils.ts +170 -0
- package/src/lib/pca.test.ts +17 -0
- package/src/lib/pca.ts +52 -0
- package/src/lib/socketio-manager.ts +664 -0
- package/src/lib/utils.ts +168 -0
- package/src/main.tsx +16 -0
- package/src/mocks/empty-module.ts +12 -0
- package/src/mocks/node-module.ts +57 -0
- package/src/polyfills.ts +37 -0
- package/src/routes/agent-detail.tsx +30 -0
- package/src/routes/agent-list.tsx +27 -0
- package/src/routes/agent-settings.tsx +48 -0
- package/src/routes/character-detail.tsx +52 -0
- package/src/routes/character-form.tsx +79 -0
- package/src/routes/character-list.tsx +38 -0
- package/src/routes/chat.tsx +128 -0
- package/src/routes/createAgent.tsx +13 -0
- package/src/routes/group-new.tsx +50 -0
- package/src/routes/group.tsx +29 -0
- package/src/routes/home.tsx +218 -0
- package/src/routes/not-found.tsx +71 -0
- package/src/test/setup.ts +154 -0
- package/src/types/crypto-browserify.d.ts +4 -0
- package/src/types/index.ts +13 -0
- package/src/types/rooms.ts +8 -0
- package/src/types.ts +84 -0
- package/src/vite-env.d.ts +40 -0
- package/tailwind.config.ts +90 -0
- package/tsconfig.json +10 -0
- package/vite.config.ts +102 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Card, CardContent } from '@/components/ui/card';
|
|
3
|
+
import { Input } from './ui/input';
|
|
4
|
+
import { Check, Eye, EyeOff, MoreVertical, Settings, X } from 'lucide-react';
|
|
5
|
+
import { Button } from './ui/button';
|
|
6
|
+
import { createElizaClient } from '@/lib/api-client-config';
|
|
7
|
+
import { ApiKeyDialog } from './api-key-dialog';
|
|
8
|
+
import { useToast } from '@/hooks/use-toast';
|
|
9
|
+
|
|
10
|
+
export default function EnvSettings() {
|
|
11
|
+
const [name, setName] = useState('');
|
|
12
|
+
const [value, setValue] = useState('');
|
|
13
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
14
|
+
const [openIndex, setOpenIndex] = useState<number | null>(null);
|
|
15
|
+
const [editingIndex, setEditingIndex] = useState<number | null>(null);
|
|
16
|
+
const [editedValue, setEditedValue] = useState('');
|
|
17
|
+
const [localEnvs, setLocalEnvs] = useState<Record<string, string>>({});
|
|
18
|
+
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
19
|
+
const [isUpdating, setIsUpdating] = useState(false);
|
|
20
|
+
const [isApiKeyDialogOpen, setIsApiKeyDialogOpen] = useState(false);
|
|
21
|
+
const { toast } = useToast();
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
25
|
+
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
|
|
26
|
+
setOpenIndex(null);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
31
|
+
return () => {
|
|
32
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
33
|
+
};
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
fetchLocalEnvs();
|
|
38
|
+
}, []);
|
|
39
|
+
|
|
40
|
+
const fetchLocalEnvs = async () => {
|
|
41
|
+
const elizaClient = createElizaClient();
|
|
42
|
+
const data = await elizaClient.system.getEnvironment();
|
|
43
|
+
setLocalEnvs(data);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const handleReset = async () => {
|
|
47
|
+
await fetchLocalEnvs();
|
|
48
|
+
|
|
49
|
+
setEditingIndex(null);
|
|
50
|
+
setOpenIndex(null);
|
|
51
|
+
setName('');
|
|
52
|
+
setValue('');
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const handleEdit = (key: string) => {
|
|
56
|
+
setEditingIndex(openIndex);
|
|
57
|
+
setEditedValue(localEnvs[key]);
|
|
58
|
+
setOpenIndex(null);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const handleRemove = (key: string) => {
|
|
62
|
+
const updatedData = { ...localEnvs };
|
|
63
|
+
delete updatedData[key];
|
|
64
|
+
setLocalEnvs(updatedData);
|
|
65
|
+
setOpenIndex(null);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const saveEdit = (key: string) => {
|
|
69
|
+
setLocalEnvs({
|
|
70
|
+
...localEnvs,
|
|
71
|
+
[key]: editedValue,
|
|
72
|
+
});
|
|
73
|
+
setEditingIndex(null);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const addEnv = () => {
|
|
77
|
+
if (!name || !value) return;
|
|
78
|
+
|
|
79
|
+
setLocalEnvs({
|
|
80
|
+
...localEnvs,
|
|
81
|
+
[name]: value,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
setName('');
|
|
85
|
+
setValue('');
|
|
86
|
+
setEditingIndex(null);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// Dummy function for onApiKeySaved
|
|
90
|
+
const handleApiKeySaved = () => {
|
|
91
|
+
console.log('API Key was saved');
|
|
92
|
+
// Potentially refetch envs or perform other actions here
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<div className="container max-w-4xl mx-auto p-6">
|
|
97
|
+
<ApiKeyDialog
|
|
98
|
+
open={isApiKeyDialogOpen}
|
|
99
|
+
onOpenChange={setIsApiKeyDialogOpen}
|
|
100
|
+
onApiKeySaved={handleApiKeySaved}
|
|
101
|
+
/>
|
|
102
|
+
|
|
103
|
+
<div className="flex items-center justify-between mb-6">
|
|
104
|
+
<div>
|
|
105
|
+
<h1 className="text-3xl font-bold">Env settings</h1>
|
|
106
|
+
<p className="text-muted-foreground mt-1">Env settings</p>
|
|
107
|
+
</div>
|
|
108
|
+
<Button onClick={() => setIsApiKeyDialogOpen(true)} aria-label="Manage API Key">
|
|
109
|
+
<Settings className="h-5 w-5" />
|
|
110
|
+
Manage API Key
|
|
111
|
+
</Button>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<Card>
|
|
115
|
+
<CardContent className="p-6">
|
|
116
|
+
<div className="space-y-6">
|
|
117
|
+
<div className="rounded-lg w-full flex flex-col gap-3">
|
|
118
|
+
<h2 className="text-xl font-bold mb-4 pb-5 ml-1">Environment Settings</h2>
|
|
119
|
+
<div className="grid grid-cols-[1fr_2fr_auto] gap-4 items-end w-full pb-4">
|
|
120
|
+
<div className="flex flex-col gap-1">
|
|
121
|
+
<label htmlFor="secret-name" className="ml-2 text-xs font-medium text-gray-400">
|
|
122
|
+
NAME
|
|
123
|
+
</label>
|
|
124
|
+
<Input
|
|
125
|
+
id="secret-name"
|
|
126
|
+
placeholder="VARIABLE_NAME"
|
|
127
|
+
value={name}
|
|
128
|
+
onChange={(e) => setName(e.target.value)}
|
|
129
|
+
/>
|
|
130
|
+
</div>
|
|
131
|
+
<div className="flex flex-col gap-1 relative">
|
|
132
|
+
<label htmlFor="secret-value" className="ml-2 text-xs font-medium text-gray-400">
|
|
133
|
+
VALUE
|
|
134
|
+
</label>
|
|
135
|
+
<div className="relative">
|
|
136
|
+
<Input
|
|
137
|
+
id="secret-value"
|
|
138
|
+
type={showPassword ? 'text' : 'password'}
|
|
139
|
+
placeholder="i9ju23nfsdf56"
|
|
140
|
+
value={value}
|
|
141
|
+
onChange={(e) => setValue(e.target.value)}
|
|
142
|
+
className="pr-10"
|
|
143
|
+
/>
|
|
144
|
+
<div
|
|
145
|
+
className="absolute inset-y-0 right-3 flex items-center cursor-pointer text-gray-500"
|
|
146
|
+
onClick={() => setShowPassword(!showPassword)}
|
|
147
|
+
>
|
|
148
|
+
{showPassword ? <EyeOff /> : <Eye />}
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
<Button className="shrink-0" onClick={addEnv}>
|
|
153
|
+
Add
|
|
154
|
+
</Button>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
{Object.keys(localEnvs).length > 0 && (
|
|
158
|
+
<div className="grid grid-cols-[1fr_2fr_auto] gap-4 mt-6 font-medium text-gray-400 border-b pb-2 ml-1">
|
|
159
|
+
<div>Name</div>
|
|
160
|
+
<div>Value</div>
|
|
161
|
+
<div>Action</div>
|
|
162
|
+
</div>
|
|
163
|
+
)}
|
|
164
|
+
|
|
165
|
+
<div className="mt-2">
|
|
166
|
+
{Object.entries(localEnvs).map(([key, value], index) => (
|
|
167
|
+
<div
|
|
168
|
+
key={index}
|
|
169
|
+
className="grid grid-cols-[1fr_2fr_auto] gap-4 items-center border-b py-2 ml-1 relative"
|
|
170
|
+
>
|
|
171
|
+
<div className="truncate max-w-48">{key}</div>
|
|
172
|
+
<div>
|
|
173
|
+
{editingIndex === index ? (
|
|
174
|
+
<div className="flex items-center gap-2">
|
|
175
|
+
<Input
|
|
176
|
+
value={editedValue}
|
|
177
|
+
onChange={(e) => setEditedValue(e.target.value)}
|
|
178
|
+
className="w-full"
|
|
179
|
+
/>
|
|
180
|
+
<Button variant="ghost" onClick={() => saveEdit(key)}>
|
|
181
|
+
<Check className="w-5 h-5 text-green-500" />
|
|
182
|
+
</Button>
|
|
183
|
+
<Button variant="ghost" onClick={() => setEditingIndex(null)}>
|
|
184
|
+
<X className="w-5 h-5 text-red-500" />
|
|
185
|
+
</Button>
|
|
186
|
+
</div>
|
|
187
|
+
) : (
|
|
188
|
+
<div className="truncate text-gray-500">Encrypted</div>
|
|
189
|
+
)}
|
|
190
|
+
</div>
|
|
191
|
+
<div className="relative">
|
|
192
|
+
<Button
|
|
193
|
+
variant="ghost"
|
|
194
|
+
className="p-2 text-gray-500"
|
|
195
|
+
onClick={() => setOpenIndex(openIndex === index ? null : index)}
|
|
196
|
+
>
|
|
197
|
+
<MoreVertical className="h-5 w-5" />
|
|
198
|
+
</Button>
|
|
199
|
+
{openIndex === index && (
|
|
200
|
+
<div
|
|
201
|
+
ref={dropdownRef}
|
|
202
|
+
className="absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-card ring-1 ring-black ring-opacity-5 z-10"
|
|
203
|
+
>
|
|
204
|
+
<div className="py-1">
|
|
205
|
+
<button
|
|
206
|
+
onClick={() => handleEdit(key)}
|
|
207
|
+
className="w-full text-left px-4 py-2 text-sm text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
|
208
|
+
>
|
|
209
|
+
Edit
|
|
210
|
+
</button>
|
|
211
|
+
<button
|
|
212
|
+
onClick={() => handleRemove(key)}
|
|
213
|
+
className="w-full text-left px-4 py-2 text-sm text-red-500 hover:bg-accent"
|
|
214
|
+
>
|
|
215
|
+
Remove
|
|
216
|
+
</button>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
)}
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
))}
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</CardContent>
|
|
227
|
+
</Card>
|
|
228
|
+
|
|
229
|
+
<div className="flex gap-2 mt-4 justify-end">
|
|
230
|
+
<Button variant="outline" onClick={handleReset}>
|
|
231
|
+
Reset
|
|
232
|
+
</Button>
|
|
233
|
+
<Button
|
|
234
|
+
type="submit"
|
|
235
|
+
disabled={isUpdating}
|
|
236
|
+
onClick={async () => {
|
|
237
|
+
setIsUpdating(true);
|
|
238
|
+
try {
|
|
239
|
+
const elizaClient = createElizaClient();
|
|
240
|
+
await elizaClient.system.updateLocalEnvironment(localEnvs);
|
|
241
|
+
toast({
|
|
242
|
+
title: 'Success',
|
|
243
|
+
description: 'Environment variables updated successfully!',
|
|
244
|
+
});
|
|
245
|
+
} catch (error) {
|
|
246
|
+
toast({
|
|
247
|
+
title: 'Error',
|
|
248
|
+
description: 'Failed to update environment variables.',
|
|
249
|
+
variant: 'destructive',
|
|
250
|
+
});
|
|
251
|
+
} finally {
|
|
252
|
+
setIsUpdating(false);
|
|
253
|
+
}
|
|
254
|
+
}}
|
|
255
|
+
>
|
|
256
|
+
Save Changes
|
|
257
|
+
</Button>
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
3
|
+
import { Card, CardContent } from '@/components/ui/card';
|
|
4
|
+
import { Button } from '@/components/ui/button';
|
|
5
|
+
import { Avatar } from '@/components/ui/avatar';
|
|
6
|
+
import type { UUID, Agent } from '@elizaos/core';
|
|
7
|
+
import type { MessageChannel as ClientMessageChannel } from '@/types';
|
|
8
|
+
import { Settings } from 'lucide-react';
|
|
9
|
+
import { formatAgentName, generateGroupName, getEntityId } from '@/lib/utils';
|
|
10
|
+
import GroupPanel from './group-panel';
|
|
11
|
+
import { useAgentsWithDetails, useChannelParticipants } from '@/hooks/use-query-hooks';
|
|
12
|
+
|
|
13
|
+
// The group prop will be a central channel, enriched with server_id for navigation context
|
|
14
|
+
// Assume group.participants might be available or added later.
|
|
15
|
+
interface GroupCardProps {
|
|
16
|
+
group: ClientMessageChannel & { server_id: UUID; participants?: Partial<Agent>[] };
|
|
17
|
+
// onEdit?: (group: ClientMessageChannel) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const GroupCard: React.FC<GroupCardProps> = ({ group /*, onEdit */ }) => {
|
|
21
|
+
const navigate = useNavigate();
|
|
22
|
+
const currentClientId = getEntityId(); // Get current client/user ID
|
|
23
|
+
const [showGroupPanel, setShowGroupPanel] = useState(false);
|
|
24
|
+
|
|
25
|
+
if (!group || !group.id) {
|
|
26
|
+
return (
|
|
27
|
+
<Card className="p-4 min-h-[180px] flex items-center justify-center text-muted-foreground">
|
|
28
|
+
Group data not available.
|
|
29
|
+
</Card>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const groupName = generateGroupName(group, group.participants || [], currentClientId);
|
|
34
|
+
|
|
35
|
+
const handleChatClick = () => {
|
|
36
|
+
navigate(`/group/${group.id}?serverId=${group.server_id}`);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const { data: agentsData } = useAgentsWithDetails();
|
|
40
|
+
const allAgents = agentsData?.agents || [];
|
|
41
|
+
|
|
42
|
+
const { data: participantsData } = useChannelParticipants(group.id);
|
|
43
|
+
const participants = participantsData?.data;
|
|
44
|
+
const participantsIds: UUID[] = participants && Array.isArray(participants) ? participants : [];
|
|
45
|
+
|
|
46
|
+
const groupAgents = participantsIds
|
|
47
|
+
? allAgents.filter((agent) => agent.id && participantsIds.includes(agent.id))
|
|
48
|
+
: [];
|
|
49
|
+
|
|
50
|
+
const handleSettings = () => {
|
|
51
|
+
setShowGroupPanel(true);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const agentNames =
|
|
55
|
+
groupAgents
|
|
56
|
+
.map((agent) => agent.name)
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
.join(', ') || 'No members';
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<>
|
|
62
|
+
<Card
|
|
63
|
+
className="w-full transition-all bg-card border border-border/50 rounded-sm"
|
|
64
|
+
data-testid="agent-card"
|
|
65
|
+
>
|
|
66
|
+
<CardContent className="p-0 relative h-full">
|
|
67
|
+
<div className="flex flex-col justify-between h-full">
|
|
68
|
+
<div className="flex items-center gap-4 p-2 h-[90%]">
|
|
69
|
+
{/* Avatar */}
|
|
70
|
+
<Avatar className="bg-[#282829] h-16 w-16 flex-shrink-0 rounded-[3px] relative overflow-hidden">
|
|
71
|
+
{groupAgents && groupAgents.length > 0 ? (
|
|
72
|
+
<div className="grid grid-cols-2 grid-rows-2 gap-1 w-full h-full p-1">
|
|
73
|
+
{groupAgents.slice(0, 3).map((agent) => {
|
|
74
|
+
const avatarUrl =
|
|
75
|
+
typeof agent.settings?.avatar === 'string' ? agent.settings.avatar : null;
|
|
76
|
+
return avatarUrl ? (
|
|
77
|
+
<img
|
|
78
|
+
key={agent.id}
|
|
79
|
+
src={avatarUrl}
|
|
80
|
+
alt={agent.name}
|
|
81
|
+
className="object-cover w-full h-full rounded-[3px]"
|
|
82
|
+
/>
|
|
83
|
+
) : (
|
|
84
|
+
<div
|
|
85
|
+
key={agent.id}
|
|
86
|
+
className="flex items-center justify-center bg-[#3F3F3F] text-xs font-medium w-full h-full rounded-[3px]"
|
|
87
|
+
>
|
|
88
|
+
{formatAgentName(agent.name)}
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
})}
|
|
92
|
+
{groupAgents.length > 3 ? (
|
|
93
|
+
<div className="flex items-center justify-center bg-[#3F3F3F] text-xs font-medium w-full h-full rounded-[3px]">
|
|
94
|
+
+{groupAgents.length - 3}
|
|
95
|
+
</div>
|
|
96
|
+
) : (
|
|
97
|
+
Array.from({ length: 4 - groupAgents.slice(0, 3).length }).map((_, idx) => (
|
|
98
|
+
<div
|
|
99
|
+
key={`empty-${idx}`}
|
|
100
|
+
className="flex items-center justify-center bg-[#2D2D2D] text-xs font-medium w-full h-full rounded-[3px]"
|
|
101
|
+
></div>
|
|
102
|
+
))
|
|
103
|
+
)}
|
|
104
|
+
</div>
|
|
105
|
+
) : (
|
|
106
|
+
<div className="flex items-center justify-center bg-muted text-lg font-medium w-full h-full">
|
|
107
|
+
{formatAgentName(groupName)}
|
|
108
|
+
</div>
|
|
109
|
+
)}
|
|
110
|
+
</Avatar>
|
|
111
|
+
|
|
112
|
+
{/* Content - Name and Description */}
|
|
113
|
+
<div className="flex-1 min-w-0">
|
|
114
|
+
<h3 className="font-semibold text-xl mb-1 truncate" title={groupName}>
|
|
115
|
+
{groupName}
|
|
116
|
+
</h3>
|
|
117
|
+
<p className="text-sm text-muted-foreground line-clamp-2 leading-relaxed">
|
|
118
|
+
{agentNames}
|
|
119
|
+
</p>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
<div className="border-t border-muted" />
|
|
123
|
+
<div className="flex items-center justify-between py-1 px-2">
|
|
124
|
+
{/* Settings button */}
|
|
125
|
+
<Button
|
|
126
|
+
variant="ghost"
|
|
127
|
+
size="sm"
|
|
128
|
+
onClick={(e) => {
|
|
129
|
+
e.stopPropagation();
|
|
130
|
+
handleSettings();
|
|
131
|
+
}}
|
|
132
|
+
className="h-8 w-8 p-0 hover:bg-muted/50 cursor-pointer"
|
|
133
|
+
>
|
|
134
|
+
<Settings className="h-4 w-4 text-muted-foreground" />
|
|
135
|
+
</Button>
|
|
136
|
+
|
|
137
|
+
{/* New Chat button - ghost variant */}
|
|
138
|
+
<Button
|
|
139
|
+
variant="outline"
|
|
140
|
+
size="sm"
|
|
141
|
+
onClick={(e) => {
|
|
142
|
+
e.stopPropagation();
|
|
143
|
+
handleChatClick();
|
|
144
|
+
}}
|
|
145
|
+
className="h-8 px-2 rounded-sm bg-muted hover:bg-muted/50 cursor-pointer"
|
|
146
|
+
>
|
|
147
|
+
Chat
|
|
148
|
+
</Button>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</CardContent>
|
|
152
|
+
</Card>
|
|
153
|
+
{showGroupPanel && (
|
|
154
|
+
<GroupPanel onClose={() => setShowGroupPanel(false)} channelId={group.id} />
|
|
155
|
+
)}
|
|
156
|
+
</>
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export default GroupCard;
|