AgentIQ_Frontend/src/pages/agent-create.tsx
2025-12-24 09:50:26 +05:30

355 lines
19 KiB
TypeScript

import { useState } from 'react';
import { Link } from '@tanstack/react-router';
import { Info, ChevronDown } from 'lucide-react';
import { APP_PATHS } from '@/routes';
import { AddToolDialog } from '@/components/ui/add-tool-dialog';
import { ConfigureMemoryDialog } from '@/components/ui/configure-memory-dialog';
import { ToolChip } from '@/components/ui/tool-chip';
import type { Tool } from '@/types';
/**
* Toggle Switch Component
* @description A toggle switch that visually represents on/off state
*/
function ToggleSwitch({ enabled }: { enabled: boolean }) {
return (
<div
className={`relative h-5 w-[35px] rounded-full transition-colors duration-200 ${
enabled ? 'bg-[#0033FF]' : 'bg-gray-300'
}`}
>
<div
className={`absolute top-0.5 h-4 w-4 rounded-full bg-white shadow-sm transition-transform duration-200 ${
enabled ? 'translate-x-[15px]' : 'translate-x-0.5'
}`}
/>
</div>
);
}
/**
* AgentCreatePage component
* @description Page for creating a new agent with configuration options
* @returns Agent creation form page
*/
export function AgentCreatePage() {
const [enableKb, setEnableKb] = useState(false);
const [enableMemory, setEnableMemory] = useState(true);
const [isToolDialogOpen, setIsToolDialogOpen] = useState(false);
const [isMemoryDialogOpen, setIsMemoryDialogOpen] = useState(false);
const [memoryValue, setMemoryValue] = useState(2);
const [editingTool, setEditingTool] = useState<Tool | null>(null);
const [tools, setTools] = useState<Tool[]>([
{ id: '1', name: 'Slack', type: 'API', color: '#ff0080' },
{ id: '2', name: 'GitHub', type: 'MCP', color: '#8fbc24' },
]);
const handleAddTool = (toolData: Omit<Tool, 'id'>) => {
const newTool: Tool = {
...toolData,
id: Date.now().toString(), // Simple ID generation
};
setTools((prev) => [...prev, newTool]);
};
const handleUpdateTool = (toolId: string, toolData: Omit<Tool, 'id'>) => {
setTools((prev) =>
prev.map((tool) => (tool.id === toolId ? { ...tool, ...toolData } : tool))
);
setEditingTool(null);
};
const handleDeleteTool = (id: string) => {
setTools((prev) => prev.filter((tool) => tool.id !== id));
};
const handleRedirectTool = (id: string) => {
// Find the tool and open configuration/update dialog
const tool = tools.find((t) => t.id === id);
if (tool) {
setEditingTool(tool);
setIsToolDialogOpen(true);
}
};
const handleDialogClose = (open: boolean) => {
setIsToolDialogOpen(open);
if (!open) {
setEditingTool(null);
}
};
return (
<div className="min-h-screen px-[50px] py-6">
<div className="mb-6">
<h1 className="font-semibold text-[20px] text-black leading-normal">
Add Agent
</h1>
</div>
<div className="flex flex-col gap-6">
{/* Main Form Card */}
<div className="bg-white border border-[rgba(0,0,0,0.1)] rounded-[24px] p-8 shadow-md">
<div className="grid gap-6 lg:grid-cols-2">
{/* Left Column */}
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-1.5">
<label className="font-medium text-sm text-black leading-[1.6]">
Name<span className="text-[#ef3125]">*</span>
</label>
<input
className="w-full h-[46px] rounded-lg border border-[#E5E8F4] bg-white px-4 py-3 text-sm text-[rgba(0,0,0,0.75)] shadow-[0px_2px_4px_0px_#EEF1F7] outline-none focus:border-[#0033FF] tracking-[0.2px]"
placeholder="Input here"
type="text"
/>
</div>
<div className="flex flex-col gap-1.5">
<label className="font-medium text-sm text-black leading-[1.6]">
Agent Description
<span className="text-[#ef3125]">*</span>
</label>
<textarea
rows={4}
className="w-full h-[135px] rounded-lg border border-[#E5E8F4] bg-white px-4 py-3 text-sm text-[rgba(0,0,0,0.75)] shadow-[0px_2px_4px_0px_#EEF1F7] outline-none focus:border-[#0033FF] tracking-[0.2px] resize-none"
placeholder="Lorem Ipsum is simply dummy text"
name="agentDescription"
/>
</div>
<div className="grid gap-8 md:grid-cols-2">
<div className="flex flex-col gap-1.5">
<label className="font-medium text-sm text-black leading-[1.6]">
LLM Provider
<span className="text-[#ef3125]">*</span>
</label>
<div className="flex items-center justify-between h-[46px] rounded-lg border border-[#E5E8F4] bg-white px-4 py-3 shadow-[0px_2px_4px_0px_#EEF1F7]">
<span className="text-sm text-[rgba(0,0,0,0.75)] tracking-[0.2px]">
Select
</span>
<ChevronDown className="shrink-0 size-5 text-[rgba(0,0,0,0.75)]" />
</div>
</div>
<div className="flex flex-col gap-1.5">
<label className="font-medium text-sm text-black leading-[1.6]">
LLM Model
<span className="text-[#ef3125]">*</span>
</label>
<div className="flex items-center justify-between h-[46px] rounded-lg border border-[#E5E8F4] bg-white px-4 py-3 shadow-[0px_2px_4px_0px_#EEF1F7]">
<span className="text-sm text-[rgba(0,0,0,0.75)] tracking-[0.2px]">
Select
</span>
<ChevronDown className="shrink-0 size-5 text-[rgba(0,0,0,0.75)]" />
</div>
</div>
</div>
</div>
{/* Right Column */}
<div className="flex flex-col gap-6 border border-[rgba(0,0,0,0.15)] rounded-[24px] p-8">
<div className="flex flex-col gap-1.5">
<label className="font-medium text-sm text-black leading-[1.6]">
Agent Role<span className="text-[#ef3125]">*</span>
</label>
<input
className="w-full h-[46px] rounded-lg border border-[#E5E8F4] bg-white px-4 py-3 text-sm text-[rgba(0,0,0,0.75)] shadow-[0px_2px_4px_0px_#EEF1F7] outline-none focus:border-[#0033FF] tracking-[0.2px]"
placeholder="Input here"
type="text"
/>
</div>
<div className="flex flex-col gap-1.5">
<label className="font-medium text-sm text-black leading-[1.6]">
Prompt<span className="text-[#ef3125]">*</span>
</label>
<input
className="w-full h-[46px] rounded-lg border border-[#E5E8F4] bg-white px-4 py-3 text-sm text-[rgba(0,0,0,0.75)] shadow-[0px_2px_4px_0px_#EEF1F7] outline-none focus:border-[#0033FF] tracking-[0.2px]"
placeholder="Your Prompt"
/>
</div>
<div className="flex flex-col gap-3">
<div className="flex items-center justify-between">
<label className="font-medium text-sm text-black leading-[1.6]">
Instruction & Suggestion
<span className="text-[#ef3125]">*</span>
</label>
<button
className="bg-[rgba(0,51,255,0.06)] border border-[#333] rounded-md px-3 py-1.5 text-xs font-medium text-[#333] hover:bg-[rgba(0,51,255,0.1)] transition-colors"
>
Improve Instruction
</button>
</div>
<textarea
rows={3}
className="w-full h-[78px] rounded-lg border border-[#E5E8F4] bg-white px-4 py-3 text-sm text-[rgba(0,0,0,0.75)] shadow-[0px_2px_4px_0px_#EEF1F7] outline-none focus:border-[#0033FF] tracking-[0.2px] resize-none"
placeholder="Lorem Ipsum is simply dummy text"
/>
</div>
</div>
</div>
</div>
{/* Features Card */}
<div className="bg-white border border-[rgba(0,0,0,0.1)] rounded-[24px] p-8 shadow-md">
<div className="flex flex-col gap-6">
<h2 className="font-semibold text-base text-black leading-[1.6]">
Features
</h2>
<div className="grid gap-6 md:grid-cols-3">
{/* Knowledge Base */}
<div className="flex flex-col gap-2">
<div
className={`flex items-center justify-between h-[56px] rounded-lg px-4 py-[13px] transition-all ${
enableKb
? 'border border-[rgba(0,51,255,0.25)] shadow-[0px_2px_12px_0px_rgba(0,51,255,0.5)]'
: 'border border-[#E5E8F4] bg-white shadow-[0px_2px_4px_0px_#EEF1F7]'
}`}
>
<div className="flex items-center gap-0.5">
<span className="font-medium text-sm text-black leading-[1.5]">
Knowledge Base
</span>
<Info className="size-4 text-black" />
</div>
<button
onClick={() => setEnableKb((v) => !v)}
className="relative shrink-0"
aria-pressed={enableKb}
>
<ToggleSwitch enabled={enableKb} />
</button>
</div>
{enableKb && (
<div className="flex items-center justify-between">
<button className="flex items-center gap-0.5 text-xs font-medium text-[#03f] leading-[1.5] hover:underline">
Configure
<img src="/Agent/redirect.svg" alt="Redirect" className="size-3.5 text-[#03f]" />
</button>
<div className="bg-white h-[22px] rounded px-1.5 py-0.5" />
</div>
)}
</div>
{/* Memory */}
<div className="flex flex-col gap-2">
<div
className={`flex items-center justify-between h-[56px] rounded-lg px-4 py-[13px] transition-all ${
enableMemory
? 'border border-[rgba(0,51,255,0.25)] shadow-[0px_2px_12px_0px_rgba(0,51,255,0.5)]'
: 'border border-[#E5E8F4] bg-white shadow-[0px_2px_4px_0px_#EEF1F7]'
}`}
>
<div className="flex items-center gap-0.5">
<span className="font-medium text-sm text-black leading-[1.5]">
Memory
</span>
<Info className="size-4 text-black" />
</div>
<button
onClick={() => setEnableMemory((v) => !v)}
className="relative shrink-0"
aria-pressed={enableMemory}
>
<ToggleSwitch enabled={enableMemory} />
</button>
</div>
{enableMemory && (
<div className="flex items-center justify-between">
<button
onClick={() => setIsMemoryDialogOpen(true)}
className="flex items-center gap-0.5 text-xs font-medium text-[#03f] leading-[1.5] hover:underline"
>
Configure
<img src="/Agent/redirect.svg" alt="Redirect" className="size-3.5 text-[#03f]" />
</button>
<span className="bg-white border border-[#e5e8f4] border-solid flex items-center px-1.5 py-0.5 rounded text-xs font-normal text-black text-center">
{memoryValue} Messages
</span>
</div>
)}
</div>
{/* Tool Configuration */}
<div className="flex items-center justify-between h-[56px] rounded-lg border border-[#E5E8F4] bg-white px-4 py-[13px] shadow-[0px_2px_8px_0px_#EEF1F7]">
<div className="flex flex-1 gap-0.5 items-center">
<span className="font-medium text-sm text-black leading-[1.6]">
Tool Configuration
</span>
<Info className="size-4 text-black" />
</div>
<button
onClick={() => {
setEditingTool(null);
setIsToolDialogOpen(true);
}}
className="bg-white border border-black border-solid flex items-center justify-center gap-1.5 px-3 py-[3px] rounded-[6px] hover:bg-gray-50 transition-colors"
>
<div className="relative size-6 flex items-center justify-center">
<img
src="/Agent/add.svg"
alt="Add"
className="size-3.5 filter brightness-0"
/> </div>
<span className="font-medium text-sm text-black leading-[1.5] text-left">
Add
</span>
</button>
</div>
</div>
{/* Divider */}
<div className="h-px bg-[#E5E8F4] w-full" />
{/* Tools Display Section */}
<div className="bg-[rgba(229,232,244,0.25)] border border-[#e5e8f4] border-solid flex flex-col items-start justify-center p-6 relative rounded-[12px] shrink-0 w-full">
<div className="flex gap-3 items-start relative shrink-0 flex-wrap">
{tools.map((tool) => (
<ToolChip
key={tool.id}
tool={tool}
onDelete={handleDeleteTool}
onRedirect={handleRedirectTool}
/>
))}
</div>
</div>
</div>
</div>
{/* Action Buttons */}
<div className="flex gap-2 justify-center font-semibold">
<Link
to={APP_PATHS.agent}
className="bg-white border border-[rgba(0,0,0,0.5)] rounded-xl px-[42px] py-[19px] w-[182px] flex items-center justify-center hover:bg-gray-50 transition-colors"
>
<span className="font-medium text-sm text-black text-center leading-[18px]">
Cancel
</span>
</Link>
<button
className="bg-[#03f] border border-[#03f] rounded-xl px-[42px] py-[19px] w-[182px] flex items-center justify-center hover:bg-[#002BCC] transition-colors"
>
<span className="font-medium text-sm text-white text-center leading-[18px]">
Create
</span>
</button>
</div>
</div>
{/* Add Tool Dialog */}
<AddToolDialog
open={isToolDialogOpen}
onOpenChange={handleDialogClose}
onAddTool={handleAddTool}
onUpdateTool={handleUpdateTool}
editingTool={editingTool}
/>
{/* Configure Memory Dialog */}
<ConfigureMemoryDialog
open={isMemoryDialogOpen}
onOpenChange={setIsMemoryDialogOpen}
initialValue={memoryValue}
onSave={setMemoryValue}
/>
</div>
);
}