Created
May 1, 2025 12:25
-
-
Save moosh3/379aeb8864bb9ce86f6aed1b689cd77a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState } from 'react'; | |
import { Users, Bot, FileText, Search, Trash2, CheckCircle, XCircle } from 'lucide-react'; | |
import Button from '../components/ui/Button'; | |
import Tabs from '../components/ui/Tabs'; | |
interface User { | |
id: string; | |
name: string; | |
email: string; | |
role: 'admin' | 'user'; | |
createdAt: Date; | |
lastLogin?: Date; | |
} | |
interface PromptRequest { | |
id: string; | |
firstName: string; | |
lastName: string; | |
jobTitle: string; | |
promptRequest: string; | |
useCase: string; | |
status: 'pending' | 'approved' | 'rejected'; | |
createdAt: Date; | |
} | |
const mockUsers: User[] = [ | |
{ | |
id: '1', | |
name: 'John Doe', | |
email: '[email protected]', | |
role: 'admin', | |
createdAt: new Date(2024, 0, 15), | |
lastLogin: new Date(2024, 2, 20), | |
}, | |
{ | |
id: '2', | |
name: 'Jane Smith', | |
email: '[email protected]', | |
role: 'user', | |
createdAt: new Date(2024, 1, 1), | |
lastLogin: new Date(2024, 2, 19), | |
}, | |
]; | |
const mockPromptRequests: PromptRequest[] = [ | |
{ | |
id: '1', | |
firstName: 'Michael', | |
lastName: 'Johnson', | |
jobTitle: 'Sales Manager', | |
promptRequest: 'Need a prompt for analyzing customer feedback', | |
useCase: 'Analyzing customer feedback to improve product features', | |
status: 'pending', | |
createdAt: new Date(2024, 2, 15), | |
}, | |
{ | |
id: '2', | |
firstName: 'Sarah', | |
lastName: 'Williams', | |
jobTitle: 'Marketing Director', | |
promptRequest: 'Content generation for social media', | |
useCase: 'Creating engaging social media posts', | |
status: 'approved', | |
createdAt: new Date(2024, 2, 10), | |
}, | |
]; | |
const Admin: React.FC = () => { | |
const [activeTab, setActiveTab] = useState('users'); | |
const [searchQuery, setSearchQuery] = useState(''); | |
const [users, setUsers] = useState<User[]>(mockUsers); | |
const [promptRequests, setPromptRequests] = useState<PromptRequest[]>(mockPromptRequests); | |
const handleDeleteUser = (userId: string) => { | |
setUsers(users.filter(user => user.id !== userId)); | |
}; | |
const handleUpdateUserRole = (userId: string, newRole: 'admin' | 'user') => { | |
setUsers(users.map(user => | |
user.id === userId ? { ...user, role: newRole } : user | |
)); | |
}; | |
const handlePromptRequestAction = (requestId: string, action: 'approved' | 'rejected') => { | |
setPromptRequests(requests => | |
requests.map(request => | |
request.id === requestId ? { ...request, status: action } : request | |
) | |
); | |
}; | |
const filteredUsers = users.filter(user => | |
user.name.toLowerCase().includes(searchQuery.toLowerCase()) || | |
user.email.toLowerCase().includes(searchQuery.toLowerCase()) | |
); | |
const filteredPromptRequests = promptRequests.filter(request => | |
request.firstName.toLowerCase().includes(searchQuery.toLowerCase()) || | |
request.lastName.toLowerCase().includes(searchQuery.toLowerCase()) || | |
request.promptRequest.toLowerCase().includes(searchQuery.toLowerCase()) | |
); | |
return ( | |
<div className="flex h-full flex-col bg-background"> | |
<div className="flex items-center justify-between border-b border-border px-6 py-4"> | |
<h1 className="text-xl font-semibold text-text">Admin Panel</h1> | |
</div> | |
<div className="flex-1 overflow-hidden p-6"> | |
<div className="mb-6"> | |
<Tabs | |
tabs={[ | |
{ id: 'users', label: 'Users' }, | |
{ id: 'prompts', label: 'Prompt Requests' }, | |
{ id: 'agents', label: 'Agents' }, | |
]} | |
activeTab={activeTab} | |
onTabChange={setActiveTab} | |
/> | |
</div> | |
<div className="mb-6"> | |
<div className="relative"> | |
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" /> | |
<input | |
type="text" | |
placeholder={`Search ${activeTab}...`} | |
value={searchQuery} | |
onChange={(e) => setSearchQuery(e.target.value)} | |
className="w-full rounded-md border border-border bg-background pl-10 pr-4 py-2 text-sm text-text placeholder-text-tertiary focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary" | |
/> | |
</div> | |
</div> | |
{activeTab === 'users' && ( | |
<div className="rounded-lg border border-border"> | |
<div className="overflow-x-auto"> | |
<table className="w-full"> | |
<thead> | |
<tr className="border-b border-border bg-background-secondary"> | |
<th className="px-6 py-3 text-left text-sm font-medium text-text">Name</th> | |
<th className="px-6 py-3 text-left text-sm font-medium text-text">Email</th> | |
<th className="px-6 py-3 text-left text-sm font-medium text-text">Role</th> | |
<th className="px-6 py-3 text-left text-sm font-medium text-text">Created</th> | |
<th className="px-6 py-3 text-left text-sm font-medium text-text">Last Login</th> | |
<th className="px-6 py-3 text-left text-sm font-medium text-text">Actions</th> | |
</tr> | |
</thead> | |
<tbody className="divide-y divide-border"> | |
{filteredUsers.map((user) => ( | |
<tr key={user.id} className="bg-background hover:bg-background-secondary"> | |
<td className="px-6 py-4"> | |
<div className="flex items-center"> | |
<div className="h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center"> | |
<span className="text-sm font-medium text-primary"> | |
{user.name.charAt(0)} | |
</span> | |
</div> | |
<span className="ml-3 text-sm text-text">{user.name}</span> | |
</div> | |
</td> | |
<td className="px-6 py-4 text-sm text-text-secondary">{user.email}</td> | |
<td className="px-6 py-4"> | |
<select | |
value={user.role} | |
onChange={(e) => handleUpdateUserRole(user.id, e.target.value as 'admin' | 'user')} | |
className="rounded-md border border-border bg-background px-2 py-1 text-sm text-text" | |
> | |
<option value="user">User</option> | |
<option value="admin">Admin</option> | |
</select> | |
</td> | |
<td className="px-6 py-4 text-sm text-text-secondary"> | |
{user.createdAt.toLocaleDateString()} | |
</td> | |
<td className="px-6 py-4 text-sm text-text-secondary"> | |
{user.lastLogin?.toLocaleDateString() || 'Never'} | |
</td> | |
<td className="px-6 py-4"> | |
<button | |
onClick={() => handleDeleteUser(user.id)} | |
className="text-red-500 hover:text-red-600" | |
> | |
<Trash2 className="h-4 w-4" /> | |
</button> | |
</td> | |
</tr> | |
))} | |
</tbody> | |
</table> | |
</div> | |
</div> | |
)} | |
{activeTab === 'prompts' && ( | |
<div className="space-y-4"> | |
{filteredPromptRequests.map((request) => ( | |
<div | |
key={request.id} | |
className="rounded-lg border border-border bg-background p-6" | |
> | |
<div className="mb-4 flex items-center justify-between"> | |
<div> | |
<h3 className="text-lg font-medium text-text"> | |
{request.firstName} {request.lastName} | |
</h3> | |
<p className="text-sm text-text-secondary">{request.jobTitle}</p> | |
</div> | |
<div className="flex items-center space-x-2"> | |
<span className={`rounded-full px-3 py-1 text-sm font-medium ${ | |
request.status === 'pending' ? 'bg-yellow-100 text-yellow-800' : | |
request.status === 'approved' ? 'bg-green-100 text-green-800' : | |
'bg-red-100 text-red-800' | |
}`}> | |
{request.status.charAt(0).toUpperCase() + request.status.slice(1)} | |
</span> | |
<span className="text-sm text-text-secondary"> | |
{request.createdAt.toLocaleDateString()} | |
</span> | |
</div> | |
</div> | |
<div className="mb-4"> | |
<h4 className="mb-1 text-sm font-medium text-text">Prompt Request</h4> | |
<p className="text-text-secondary">{request.promptRequest}</p> | |
</div> | |
<div className="mb-4"> | |
<h4 className="mb-1 text-sm font-medium text-text">Use Case</h4> | |
<p className="text-text-secondary">{request.useCase}</p> | |
</div> | |
{request.status === 'pending' && ( | |
<div className="flex justify-end space-x-3"> | |
<Button | |
variant="outline" | |
onClick={() => handlePromptRequestAction(request.id, 'rejected')} | |
icon={<XCircle className="h-4 w-4" />} | |
> | |
Reject | |
</Button> | |
<Button | |
variant="primary" | |
onClick={() => handlePromptRequestAction(request.id, 'approved')} | |
icon={<CheckCircle className="h-4 w-4" />} | |
> | |
Approve | |
</Button> | |
</div> | |
)} | |
</div> | |
))} | |
</div> | |
)} | |
{activeTab === 'agents' && ( | |
<div className="rounded-lg border border-border"> | |
<div className="overflow-x-auto"> | |
<table className="w-full"> | |
<thead> | |
<tr className="border-b border-border bg-background-secondary"> | |
<th className="px-6 py-3 text-left text-sm font-medium text-text">Name</th> | |
<th className="px-6 py-3 text-left text-sm font-medium text-text">Category</th> | |
<th className="px-6 py-3 text-left text-sm font-medium text-text">Created By</th> | |
<th className="px-6 py-3 text-left text-sm font-medium text-text">Created At</th> | |
<th className="px-6 py-3 text-left text-sm font-medium text-text">Actions</th> | |
</tr> | |
</thead> | |
<tbody className="divide-y divide-border"> | |
{/* Add agent rows here when implementing agent management */} | |
</tbody> | |
</table> | |
</div> | |
</div> | |
)} | |
</div> | |
</div> | |
); | |
}; | |
export default Admin; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState } from 'react'; | |
import Sidebar from './components/Sidebar'; | |
import Dashboard from './pages/Dashboard'; | |
import Chat from './components/Chat'; | |
import Content from './pages/Content'; | |
import Runs from './pages/Runs'; | |
import RunConfig from './pages/RunConfig'; | |
import RunOutput from './pages/RunOutput'; | |
import Teams from './pages/Teams'; | |
import Prompts from './pages/Prompts'; | |
import Settings from './pages/Settings'; | |
import Landing from './pages/Landing'; | |
import WorkflowEditor from './components/workflow/WorkflowEditor'; | |
import { Agent } from './types'; | |
import { useAuthStore } from './stores/authStore'; | |
function App() { | |
const { user } = useAuthStore(); | |
const [sidebarCollapsed, setSidebarCollapsed] = useState(false); | |
const [currentChat, setCurrentChat] = useState<Agent | null>(null); | |
const [currentView, setCurrentView] = useState<'dashboard' | 'chat' | 'content' | 'runs' | 'run-config' | 'run-output' | 'teams' | 'workflows' | 'prompts' | 'settings'>('dashboard'); | |
const [selectedAgent, setSelectedAgent] = useState<Agent | null>(null); | |
const handleStartChat = (agent: Agent) => { | |
setCurrentChat(agent); | |
setCurrentView('chat'); | |
}; | |
const handleNavigate = (view: 'dashboard' | 'chat' | 'content' | 'runs' | 'teams' | 'workflows' | 'prompts' | 'settings') => { | |
setCurrentView(view); | |
if (view === 'chat' && !currentChat) { | |
setCurrentChat({ | |
id: 'default-agent', | |
name: 'AI Assistant', | |
description: 'Your general-purpose AI assistant', | |
icon: 'default', | |
category: 'popular' | |
}); | |
} | |
}; | |
const handleAgentSelect = (agent: Agent) => { | |
setSelectedAgent(agent); | |
setCurrentView('run-config'); | |
}; | |
const handleRunAgent = (config: any) => { | |
setCurrentView('run-output'); | |
}; | |
if (!user) { | |
return <Landing onSignIn={() => useAuthStore.getState().signIn('[email protected]', 'password')} />; | |
} | |
return ( | |
<div className="flex h-screen overflow-hidden"> | |
<Sidebar | |
collapsed={sidebarCollapsed} | |
onToggle={() => setSidebarCollapsed(!sidebarCollapsed)} | |
onStartChat={handleStartChat} | |
onNavigate={handleNavigate} | |
currentView={currentView} | |
/> | |
<div className="flex-1 overflow-auto"> | |
{currentView === 'chat' ? ( | |
<Chat | |
agent={currentChat!} | |
onBack={() => { | |
setCurrentView('dashboard'); | |
setCurrentChat(null); | |
}} | |
/> | |
) : currentView === 'content' ? ( | |
<Content /> | |
) : currentView === 'runs' ? ( | |
<Runs /> | |
) : currentView === 'teams' ? ( | |
<Teams /> | |
) : currentView === 'workflows' ? ( | |
<WorkflowEditor /> | |
) : currentView === 'prompts' ? ( | |
<Prompts /> | |
) : currentView === 'settings' ? ( | |
<Settings /> | |
) : currentView === 'run-config' && selectedAgent ? ( | |
<RunConfig | |
agent={selectedAgent} | |
onBack={() => { | |
setCurrentView('dashboard'); | |
setSelectedAgent(null); | |
}} | |
onRun={handleRunAgent} | |
/> | |
) : currentView === 'run-output' && selectedAgent ? ( | |
<RunOutput | |
agent={selectedAgent} | |
onBack={() => { | |
setCurrentView('dashboard'); | |
setSelectedAgent(null); | |
}} | |
/> | |
) : ( | |
<Dashboard | |
onStartChat={handleStartChat} | |
onAgentSelect={handleAgentSelect} | |
/> | |
)} | |
</div> | |
</div> | |
); | |
} | |
export default App; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState } from 'react'; | |
import { Camera, User, Settings as SettingsIcon } from 'lucide-react'; | |
import Button from '../components/ui/Button'; | |
import Tabs from '../components/ui/Tabs'; | |
import Admin from './Admin'; | |
import { useAuthStore } from '../stores/authStore'; | |
const Settings: React.FC = () => { | |
const { user } = useAuthStore(); | |
const [activeTab, setActiveTab] = useState('profile'); | |
const [name, setName] = useState(user?.name || ''); | |
const [email, setEmail] = useState(user?.email || ''); | |
const [avatar, setAvatar] = useState(user?.avatar_url || ''); | |
const handleSave = () => { | |
// Handle saving user profile | |
console.log('Saving profile:', { name, email, avatar }); | |
}; | |
return ( | |
<div className="flex h-full flex-col bg-background"> | |
<div className="flex items-center justify-between border-b border-border px-6 py-4"> | |
<div className="flex items-center space-x-3"> | |
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-primary/10"> | |
<SettingsIcon className="h-4 w-4 text-primary" /> | |
</div> | |
<h1 className="text-xl font-semibold text-text">Settings</h1> | |
</div> | |
</div> | |
<div className="flex-1 overflow-hidden"> | |
<div className="h-full flex"> | |
<div className="w-64 border-r border-border bg-background p-4"> | |
<Tabs | |
tabs={[ | |
{ id: 'profile', label: 'Profile' }, | |
...(user?.role === 'admin' ? [{ id: 'admin', label: 'Admin' }] : []), | |
]} | |
activeTab={activeTab} | |
onTabChange={setActiveTab} | |
/> | |
</div> | |
<div className="flex-1 p-6 overflow-y-auto"> | |
{activeTab === 'profile' ? ( | |
<div className="max-w-2xl"> | |
<div className="mb-8"> | |
<div className="flex items-center space-x-4"> | |
<div className="relative"> | |
{avatar ? ( | |
<img | |
src={avatar} | |
alt={name} | |
className="h-20 w-20 rounded-full object-cover" | |
/> | |
) : ( | |
<div className="flex h-20 w-20 items-center justify-center rounded-full bg-primary/10"> | |
<User className="h-8 w-8 text-primary" /> | |
</div> | |
)} | |
<button className="absolute bottom-0 right-0 rounded-full bg-white p-1.5 shadow-md hover:bg-gray-50"> | |
<Camera className="h-4 w-4 text-gray-600" /> | |
</button> | |
</div> | |
<div> | |
<h2 className="text-lg font-medium text-text">{name}</h2> | |
<p className="text-sm text-text-secondary">{email}</p> | |
</div> | |
</div> | |
</div> | |
<div className="space-y-6"> | |
<div> | |
<label className="mb-1 block text-sm font-medium text-text"> | |
Name | |
</label> | |
<input | |
type="text" | |
value={name} | |
onChange={(e) => setName(e.target.value)} | |
className="w-full rounded-md border border-border bg-background px-4 py-2 text-sm text-text placeholder-text-tertiary focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary" | |
/> | |
</div> | |
<div> | |
<label className="mb-1 block text-sm font-medium text-text"> | |
</label> | |
<input | |
type="email" | |
value={email} | |
onChange={(e) => setEmail(e.target.value)} | |
className="w-full rounded-md border border-border bg-background px-4 py-2 text-sm text-text placeholder-text-tertiary focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary" | |
/> | |
</div> | |
<div> | |
<Button variant="primary" onClick={handleSave}> | |
Save Changes | |
</Button> | |
</div> | |
</div> | |
</div> | |
) : activeTab === 'admin' && user?.role === 'admin' ? ( | |
<Admin /> | |
) : null} | |
</div> | |
</div> | |
</div> | |
</div> | |
); | |
}; | |
export default Settings; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export interface User { | |
id: string; | |
email: string; | |
name: string; | |
avatar_url?: string; | |
role?: 'admin' | 'user'; | |
} | |
export interface Agent { | |
id: string; | |
name: string; | |
description: string; | |
icon: string; | |
category: AgentCategory; | |
isCustom?: boolean; | |
createdAt?: Date; | |
schedule?: Schedule; | |
variables?: AgentVariable[]; | |
instructions?: string; | |
} | |
export type AgentCategory = | |
| 'customer-service' | |
| 'sales' | |
| 'engineering' | |
| 'support' | |
| 'marketing' | |
| 'it' | |
| 'hr' | |
| 'popular'; | |
export interface AgentVariable { | |
name: string; | |
description: string; | |
value?: string; | |
} | |
export interface Schedule { | |
enabled: boolean; | |
frequency: 'hourly' | 'daily' | 'weekly' | 'monthly'; | |
interval: number; | |
time?: string; | |
days?: number[]; | |
date?: number; | |
timezone: string; | |
lastRun?: Date; | |
nextRun?: Date; | |
} | |
export interface Team { | |
id: string; | |
name: string; | |
description: string; | |
type: 'route' | 'coordinate' | 'collaborate'; | |
agents: Agent[]; | |
createdAt: Date; | |
} | |
export interface Run { | |
id: string; | |
startTime: Date; | |
endTime?: Date; | |
triggeredBy: { | |
id: string; | |
name: string; | |
avatar?: string; | |
}; | |
status: 'running' | 'completed' | 'failed'; | |
duration?: number; | |
logs: string[]; | |
input: Record<string, any>; | |
output?: Record<string, any>; | |
error?: string; | |
resourceUsage?: { | |
cpuTime: number; | |
memoryUsage: number; | |
apiCalls: number; | |
}; | |
} | |
export interface AgentRun extends Run { | |
agentId: string; | |
agentName: string; | |
} | |
export interface TeamRun extends Run { | |
teamId: string; | |
teamName: string; | |
teamType: Team['type']; | |
agentRuns: AgentRun[]; | |
} | |
export interface FilterOption { | |
id: string; | |
label: string; | |
value: string; | |
} | |
export interface TabOption { | |
id: string; | |
label: string; | |
count?: number; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment