changes code quality
This commit is contained in:
parent
6c38cc160a
commit
e812486fe0
@ -197,8 +197,19 @@ export function ForgotPasswordModal({
|
|||||||
}, 800);
|
}, 800);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleResendCode = (): void => {
|
/**
|
||||||
console.log('Resend code to:', email);
|
* Handle resend OTP code
|
||||||
|
* @description Resends the OTP verification code to the user's email
|
||||||
|
* @throws {Error} When resend request fails
|
||||||
|
*/
|
||||||
|
const handleResendCode = async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
// TODO: Implement resend OTP API call
|
||||||
|
// await resendOtpCode(email);
|
||||||
|
} catch (error) {
|
||||||
|
// Error handling will be implemented with proper logging service
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBackdropClick = (): void => handleClose();
|
const handleBackdropClick = (): void => handleClose();
|
||||||
|
|||||||
@ -7,8 +7,11 @@
|
|||||||
* AgentCard component props
|
* AgentCard component props
|
||||||
*/
|
*/
|
||||||
interface AgentCardProps {
|
interface AgentCardProps {
|
||||||
|
/** Agent title/name */
|
||||||
title: string;
|
title: string;
|
||||||
|
/** Array of tag labels */
|
||||||
tags: string[];
|
tags: string[];
|
||||||
|
/** Agent description text */
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,9 +19,13 @@ interface AgentCardProps {
|
|||||||
* AgentCard component
|
* AgentCard component
|
||||||
* @description Card showing agent details with tags
|
* @description Card showing agent details with tags
|
||||||
* @param props - Component props
|
* @param props - Component props
|
||||||
* @returns AgentCard element
|
* @returns {JSX.Element} AgentCard element
|
||||||
*/
|
*/
|
||||||
export function AgentCard({ title, tags, description }: AgentCardProps) {
|
export function AgentCard({
|
||||||
|
title,
|
||||||
|
tags,
|
||||||
|
description,
|
||||||
|
}: AgentCardProps): JSX.Element {
|
||||||
// Define your colors in order
|
// Define your colors in order
|
||||||
const tagColors = [
|
const tagColors = [
|
||||||
"bg-[#E5E8F4]", // 1st tag (index 0)
|
"bg-[#E5E8F4]", // 1st tag (index 0)
|
||||||
|
|||||||
@ -26,9 +26,12 @@ interface AgentsSectionProps {
|
|||||||
* Agents section component
|
* Agents section component
|
||||||
* @description Displays agents with tabs and pagination
|
* @description Displays agents with tabs and pagination
|
||||||
* @param props - Component props
|
* @param props - Component props
|
||||||
* @returns AgentsSection element
|
* @returns {JSX.Element} AgentsSection element
|
||||||
*/
|
*/
|
||||||
export function AgentsSection({ agents, itemsPerPage = 6 }: AgentsSectionProps) {
|
export function AgentsSection({
|
||||||
|
agents,
|
||||||
|
itemsPerPage = 6,
|
||||||
|
}: AgentsSectionProps): JSX.Element {
|
||||||
const [activeTab, setActiveTab] = useState<'all' | 'my'>('all');
|
const [activeTab, setActiveTab] = useState<'all' | 'my'>('all');
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
|
||||||
@ -57,9 +60,10 @@ export function AgentsSection({ agents, itemsPerPage = 6 }: AgentsSectionProps)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle page change
|
* Handle page change
|
||||||
|
* @description Updates the current page number
|
||||||
* @param page - New page number (1-indexed)
|
* @param page - New page number (1-indexed)
|
||||||
*/
|
*/
|
||||||
const handlePageChange = (page: number) => {
|
const handlePageChange = (page: number): void => {
|
||||||
setCurrentPage(page);
|
setCurrentPage(page);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Metric card component props
|
||||||
|
*/
|
||||||
interface MetricCardProps {
|
interface MetricCardProps {
|
||||||
|
/** Card title text */
|
||||||
title: string;
|
title: string;
|
||||||
|
/** Card subtitle text */
|
||||||
subtitle: string;
|
subtitle: string;
|
||||||
|
/** Display value */
|
||||||
value: string;
|
value: string;
|
||||||
|
/** Gradient color scheme */
|
||||||
gradient: 'blue-teal' | 'pink-purple' | 'orange-yellow' | 'blue-purple';
|
gradient: 'blue-teal' | 'pink-purple' | 'orange-yellow' | 'blue-purple';
|
||||||
|
/** Optional image URL for card decoration */
|
||||||
imageUrl?: string;
|
imageUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gradient style type
|
||||||
|
*/
|
||||||
type GradientStyle = {
|
type GradientStyle = {
|
||||||
backgroundImage?: string;
|
backgroundImage?: string;
|
||||||
background?: string;
|
background?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function MetricCard({ title, subtitle, value, gradient, imageUrl }: MetricCardProps) {
|
/**
|
||||||
|
* MetricCard component
|
||||||
|
* @description Displays a metric card with gradient background and optional image
|
||||||
|
* @param props - Component props
|
||||||
|
* @returns MetricCard element
|
||||||
|
*/
|
||||||
|
export function MetricCard({
|
||||||
|
title,
|
||||||
|
subtitle,
|
||||||
|
value,
|
||||||
|
gradient,
|
||||||
|
imageUrl,
|
||||||
|
}: MetricCardProps): JSX.Element {
|
||||||
const gradientStyles: Record<MetricCardProps['gradient'], GradientStyle> = {
|
const gradientStyles: Record<MetricCardProps['gradient'], GradientStyle> = {
|
||||||
'blue-teal': {
|
'blue-teal': {
|
||||||
backgroundImage: 'linear-gradient(16.03674192372833deg, rgba(0, 27, 47, 1) 10.549%, rgba(6, 38, 168, 1) 30.146%, rgba(3, 154, 152, 1) 77.418%)',
|
backgroundImage: 'linear-gradient(16.03674192372833deg, rgba(0, 27, 47, 1) 10.549%, rgba(6, 38, 168, 1) 30.146%, rgba(3, 154, 152, 1) 77.418%)',
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
|
|
||||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pagination component props
|
||||||
|
*/
|
||||||
interface PaginationProps {
|
interface PaginationProps {
|
||||||
|
/** Current active page number (1-indexed) */
|
||||||
currentPage: number;
|
currentPage: number;
|
||||||
|
/** Total number of pages */
|
||||||
totalPages: number;
|
totalPages: number;
|
||||||
|
/** Callback when page changes */
|
||||||
onPageChange: (page: number) => void;
|
onPageChange: (page: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -11,12 +17,17 @@ interface PaginationProps {
|
|||||||
* Pagination component
|
* Pagination component
|
||||||
* @description Displays pagination controls with page numbers and navigation arrows
|
* @description Displays pagination controls with page numbers and navigation arrows
|
||||||
* @param props - Component props
|
* @param props - Component props
|
||||||
* @returns Pagination element
|
* @returns {JSX.Element} Pagination element
|
||||||
*/
|
*/
|
||||||
export function Pagination({ currentPage, totalPages, onPageChange }: PaginationProps) {
|
export function Pagination({
|
||||||
|
currentPage,
|
||||||
|
totalPages,
|
||||||
|
onPageChange,
|
||||||
|
}: PaginationProps): JSX.Element {
|
||||||
/**
|
/**
|
||||||
* Generate page numbers to display
|
* Generate page numbers to display
|
||||||
* @returns Array of page numbers and ellipsis markers
|
* @description Calculates which page numbers to show based on current page and total pages
|
||||||
|
* @returns {Array<number | 'ellipsis'>} Array of page numbers and ellipsis markers
|
||||||
*/
|
*/
|
||||||
const getPageNumbers = (): (number | 'ellipsis')[] => {
|
const getPageNumbers = (): (number | 'ellipsis')[] => {
|
||||||
const pages: (number | 'ellipsis')[] = [];
|
const pages: (number | 'ellipsis')[] = [];
|
||||||
@ -58,8 +69,9 @@ export function Pagination({ currentPage, totalPages, onPageChange }: Pagination
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle previous page navigation
|
* Handle previous page navigation
|
||||||
|
* @description Navigates to the previous page if available
|
||||||
*/
|
*/
|
||||||
const handlePrevious = () => {
|
const handlePrevious = (): void => {
|
||||||
if (currentPage > 1) {
|
if (currentPage > 1) {
|
||||||
onPageChange(currentPage - 1);
|
onPageChange(currentPage - 1);
|
||||||
}
|
}
|
||||||
@ -67,8 +79,9 @@ export function Pagination({ currentPage, totalPages, onPageChange }: Pagination
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle next page navigation
|
* Handle next page navigation
|
||||||
|
* @description Navigates to the next page if available
|
||||||
*/
|
*/
|
||||||
const handleNext = () => {
|
const handleNext = (): void => {
|
||||||
if (currentPage < totalPages) {
|
if (currentPage < totalPages) {
|
||||||
onPageChange(currentPage + 1);
|
onPageChange(currentPage + 1);
|
||||||
}
|
}
|
||||||
@ -76,9 +89,10 @@ export function Pagination({ currentPage, totalPages, onPageChange }: Pagination
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle page number click
|
* Handle page number click
|
||||||
|
* @description Navigates to the specified page if valid
|
||||||
* @param page - Page number to navigate to
|
* @param page - Page number to navigate to
|
||||||
*/
|
*/
|
||||||
const handlePageClick = (page: number) => {
|
const handlePageClick = (page: number): void => {
|
||||||
if (page !== currentPage && page >= 1 && page <= totalPages) {
|
if (page !== currentPage && page >= 1 && page <= totalPages) {
|
||||||
onPageChange(page);
|
onPageChange(page);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,9 +5,9 @@ import { APP_PATHS } from '@/routes';
|
|||||||
/**
|
/**
|
||||||
* Sidebar component
|
* Sidebar component
|
||||||
* @description Left sidebar navigation with icon menu
|
* @description Left sidebar navigation with icon menu
|
||||||
* @returns Sidebar element
|
* @returns {JSX.Element} Sidebar element
|
||||||
*/
|
*/
|
||||||
export function Sidebar() {
|
export function Sidebar(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<aside className="fixed left-4 top-20 bottom-4 w-14 md:left-6 md:top-24 md:bottom-6 md:w-16 bg-gradient-to-b from-[#00A1A0] to-[#00166D] flex flex-col items-center py-4 md:py-6 gap-4 md:gap-6 z-50 rounded-xl md:rounded-2xl shadow-xl hidden md:flex">
|
<aside className="fixed left-4 top-20 bottom-4 w-14 md:left-6 md:top-24 md:bottom-6 md:w-16 bg-gradient-to-b from-[#00A1A0] to-[#00166D] flex flex-col items-center py-4 md:py-6 gap-4 md:gap-6 z-50 rounded-xl md:rounded-2xl shadow-xl hidden md:flex">
|
||||||
{/* Navigation Icons */}
|
{/* Navigation Icons */}
|
||||||
|
|||||||
@ -15,10 +15,11 @@ interface RootLayoutProps {
|
|||||||
/**
|
/**
|
||||||
* RootLayout component
|
* RootLayout component
|
||||||
* @description Wraps all pages with consistent sidebar and header layout
|
* @description Wraps all pages with consistent sidebar and header layout
|
||||||
* @param children - Page content to render
|
* @param props - Component props
|
||||||
* @returns RootLayout element
|
* @param props.children - Page content to render
|
||||||
|
* @returns {JSX.Element} RootLayout element
|
||||||
*/
|
*/
|
||||||
export function RootLayout({ children }: RootLayoutProps) {
|
export function RootLayout({ children }: RootLayoutProps): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="min-h-screen"
|
className="min-h-screen"
|
||||||
|
|||||||
@ -16,11 +16,19 @@ import {
|
|||||||
import { useClickOutside } from '@/hooks';
|
import { useClickOutside } from '@/hooks';
|
||||||
import type { Tool } from '@/types';
|
import type { Tool } from '@/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AddToolDialog component props
|
||||||
|
*/
|
||||||
interface AddToolDialogProps {
|
interface AddToolDialogProps {
|
||||||
|
/** Whether the dialog is open */
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
/** Callback when dialog open state changes */
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
|
/** Callback when a new tool is added */
|
||||||
onAddTool?: (tool: Omit<Tool, 'id'>) => void;
|
onAddTool?: (tool: Omit<Tool, 'id'>) => void;
|
||||||
|
/** Callback when an existing tool is updated */
|
||||||
onUpdateTool?: (toolId: string, tool: Omit<Tool, 'id'>) => void;
|
onUpdateTool?: (toolId: string, tool: Omit<Tool, 'id'>) => void;
|
||||||
|
/** Tool being edited, if any */
|
||||||
editingTool?: Tool | null;
|
editingTool?: Tool | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,12 +49,17 @@ const SAVE_BUTTON_CLASS =
|
|||||||
const SAVE_BUTTON_TEXT_CLASS = 'font-semibold leading-[18px] not-italic text-[16px] text-center text-white';
|
const SAVE_BUTTON_TEXT_CLASS = 'font-semibold leading-[18px] not-italic text-[16px] text-center text-white';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AddToolDialog component
|
* Get initial state for the dialog
|
||||||
* @description Modal dialog for adding tools with API/MCP selection
|
* @description Determines initial state based on editing tool
|
||||||
* @param open - Whether the dialog is open
|
* @param editingTool - Tool being edited, if any
|
||||||
* @param onOpenChange - Callback when dialog open state changes
|
* @returns Initial state with selected type and tool
|
||||||
*/
|
*/
|
||||||
const getInitialState = (editingTool: Tool | null | undefined) => {
|
const getInitialState = (
|
||||||
|
editingTool: Tool | null | undefined
|
||||||
|
): {
|
||||||
|
selectedType: 'API' | 'MCP';
|
||||||
|
selectedTool: typeof toolOptions[0] | null;
|
||||||
|
} => {
|
||||||
if (editingTool) {
|
if (editingTool) {
|
||||||
const toolOption = toolOptions.find((opt) => opt.displayName === editingTool.name);
|
const toolOption = toolOptions.find((opt) => opt.displayName === editingTool.name);
|
||||||
return {
|
return {
|
||||||
@ -60,7 +73,19 @@ const getInitialState = (editingTool: Tool | null | undefined) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function AddToolDialog({ open, onOpenChange, onAddTool, onUpdateTool, editingTool }: AddToolDialogProps) {
|
/**
|
||||||
|
* AddToolDialog component
|
||||||
|
* @description Modal dialog for adding and configuring tools with API/MCP selection
|
||||||
|
* @param props - Component props
|
||||||
|
* @returns {JSX.Element} AddToolDialog element
|
||||||
|
*/
|
||||||
|
export function AddToolDialog({
|
||||||
|
open,
|
||||||
|
onOpenChange,
|
||||||
|
onAddTool,
|
||||||
|
onUpdateTool,
|
||||||
|
editingTool,
|
||||||
|
}: AddToolDialogProps): JSX.Element {
|
||||||
const initialState = useMemo(() => getInitialState(editingTool), [editingTool]);
|
const initialState = useMemo(() => getInitialState(editingTool), [editingTool]);
|
||||||
const [selectedType, setSelectedType] = useState<'API' | 'MCP'>(initialState.selectedType);
|
const [selectedType, setSelectedType] = useState<'API' | 'MCP'>(initialState.selectedType);
|
||||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||||
@ -80,16 +105,29 @@ export function AddToolDialog({ open, onOpenChange, onAddTool, onUpdateTool, edi
|
|||||||
|
|
||||||
const dropdownRef = useClickOutside<HTMLDivElement>(() => setIsDropdownOpen(false), isDropdownOpen);
|
const dropdownRef = useClickOutside<HTMLDivElement>(() => setIsDropdownOpen(false), isDropdownOpen);
|
||||||
|
|
||||||
const handleToolSelect = (tool: typeof toolOptions[0]) => {
|
/**
|
||||||
|
* Handle tool selection from dropdown
|
||||||
|
* @description Sets the selected tool and closes dropdown
|
||||||
|
* @param tool - Selected tool option
|
||||||
|
*/
|
||||||
|
const handleToolSelect = (tool: typeof toolOptions[0]): void => {
|
||||||
setSelectedTool(tool);
|
setSelectedTool(tool);
|
||||||
setIsDropdownOpen(false);
|
setIsDropdownOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleToggleDropdown = () => {
|
/**
|
||||||
|
* Toggle dropdown open/close state
|
||||||
|
* @description Switches dropdown visibility
|
||||||
|
*/
|
||||||
|
const handleToggleDropdown = (): void => {
|
||||||
setIsDropdownOpen((prev) => !prev);
|
setIsDropdownOpen((prev) => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSave = () => {
|
/**
|
||||||
|
* Handle save action
|
||||||
|
* @description Saves the tool configuration (add or update)
|
||||||
|
*/
|
||||||
|
const handleSave = (): void => {
|
||||||
if (!selectedTool) return;
|
if (!selectedTool) return;
|
||||||
|
|
||||||
const toolData = {
|
const toolData = {
|
||||||
@ -109,13 +147,23 @@ export function AddToolDialog({ open, onOpenChange, onAddTool, onUpdateTool, edi
|
|||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
/**
|
||||||
|
* Handle dialog close
|
||||||
|
* @description Closes dialog and resets state
|
||||||
|
*/
|
||||||
|
const handleClose = (): void => {
|
||||||
setIsDropdownOpen(false);
|
setIsDropdownOpen(false);
|
||||||
setSelectedTool(null);
|
setSelectedTool(null);
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const radioButtonClass = (type: 'API' | 'MCP') =>
|
/**
|
||||||
|
* Get radio button class based on selection state
|
||||||
|
* @description Returns CSS classes for radio button styling
|
||||||
|
* @param type - Radio button type (API or MCP)
|
||||||
|
* @returns CSS class string
|
||||||
|
*/
|
||||||
|
const radioButtonClass = (type: 'API' | 'MCP'): string =>
|
||||||
`relative size-5 rounded-full border-2 flex items-center justify-center transition-all ${
|
`relative size-5 rounded-full border-2 flex items-center justify-center transition-all ${
|
||||||
selectedType === type ? 'border-[#0033FF]' : 'border-[#E5E8F4]'
|
selectedType === type ? 'border-[#0033FF]' : 'border-[#E5E8F4]'
|
||||||
}`;
|
}`;
|
||||||
@ -130,7 +178,13 @@ export function AddToolDialog({ open, onOpenChange, onAddTool, onUpdateTool, edi
|
|||||||
|
|
||||||
const dropdownItemBaseClass =
|
const dropdownItemBaseClass =
|
||||||
'w-full px-4 py-[13px] text-left font-normal text-sm leading-[20px] transition-colors border-b border-[#E5E8F4] last:border-b-0';
|
'w-full px-4 py-[13px] text-left font-normal text-sm leading-[20px] transition-colors border-b border-[#E5E8F4] last:border-b-0';
|
||||||
const dropdownItemClass = (isSelected: boolean) =>
|
/**
|
||||||
|
* Get dropdown item class based on selection state
|
||||||
|
* @description Returns CSS classes for dropdown item styling
|
||||||
|
* @param isSelected - Whether the item is selected
|
||||||
|
* @returns CSS class string
|
||||||
|
*/
|
||||||
|
const dropdownItemClass = (isSelected: boolean): string =>
|
||||||
`${dropdownItemBaseClass} ${
|
`${dropdownItemBaseClass} ${
|
||||||
isSelected
|
isSelected
|
||||||
? 'bg-[rgba(0,51,255,0.1)] text-[#0033FF]'
|
? 'bg-[rgba(0,51,255,0.1)] text-[#0033FF]'
|
||||||
|
|||||||
@ -14,28 +14,50 @@ import {
|
|||||||
} from './dialog';
|
} from './dialog';
|
||||||
import { useEscapeKey, useBodyScrollLock } from '@/hooks';
|
import { useEscapeKey, useBodyScrollLock } from '@/hooks';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigureMemoryDialog component props
|
||||||
|
*/
|
||||||
interface ConfigureMemoryDialogProps {
|
interface ConfigureMemoryDialogProps {
|
||||||
|
/** Whether the dialog is open */
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
/** Callback when dialog open state changes */
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
|
/** Initial memory value (default: 2) */
|
||||||
initialValue?: number;
|
initialValue?: number;
|
||||||
|
/** Callback when memory value is saved */
|
||||||
onSave?: (value: number) => void;
|
onSave?: (value: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ConfigureMemoryDialog component
|
* Minimum memory value
|
||||||
* @description Modal dialog for configuring memory settings
|
|
||||||
* @param open - Whether the dialog is open
|
|
||||||
* @param onOpenChange - Callback when dialog open state changes
|
|
||||||
* @param initialValue - Initial memory value (default: 2)
|
|
||||||
* @param onSave - Callback when memory is saved
|
|
||||||
*/
|
*/
|
||||||
const MIN_VALUE = 2;
|
const MIN_VALUE = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum memory value
|
||||||
|
*/
|
||||||
const MAX_VALUE = 10;
|
const MAX_VALUE = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clamp value between min and max
|
||||||
|
* @description Ensures value is within bounds
|
||||||
|
* @param value - Value to clamp
|
||||||
|
* @param min - Minimum value
|
||||||
|
* @param max - Maximum value
|
||||||
|
* @returns Clamped value
|
||||||
|
*/
|
||||||
const clampValue = (value: number, min: number, max: number): number => {
|
const clampValue = (value: number, min: number, max: number): number => {
|
||||||
return Math.max(min, Math.min(max, value));
|
return Math.max(min, Math.min(max, value));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate percentage for slider
|
||||||
|
* @description Calculates percentage position for slider thumb
|
||||||
|
* @param value - Current value
|
||||||
|
* @param min - Minimum value
|
||||||
|
* @param max - Maximum value
|
||||||
|
* @returns Percentage (0-100)
|
||||||
|
*/
|
||||||
const calculatePercentage = (value: number, min: number, max: number): number => {
|
const calculatePercentage = (value: number, min: number, max: number): number => {
|
||||||
return ((value - min) / (max - min)) * 100;
|
return ((value - min) / (max - min)) * 100;
|
||||||
};
|
};
|
||||||
@ -61,12 +83,18 @@ const SLIDER_THUMB_CLASS =
|
|||||||
'absolute top-[-5px] size-[18px] bg-white rounded-full border-2 border-[#0033FF] shadow-md pointer-events-none transition-all duration-200 z-20';
|
'absolute top-[-5px] size-[18px] bg-white rounded-full border-2 border-[#0033FF] shadow-md pointer-events-none transition-all duration-200 z-20';
|
||||||
const MAX_LABEL_CLASS = 'font-medium leading-4 not-italic relative shrink-0 text-xs text-black';
|
const MAX_LABEL_CLASS = 'font-medium leading-4 not-italic relative shrink-0 text-xs text-black';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConfigureMemoryDialog component
|
||||||
|
* @description Modal dialog for configuring memory settings with slider
|
||||||
|
* @param props - Component props
|
||||||
|
* @returns {JSX.Element} ConfigureMemoryDialog element
|
||||||
|
*/
|
||||||
export function ConfigureMemoryDialog({
|
export function ConfigureMemoryDialog({
|
||||||
open,
|
open,
|
||||||
onOpenChange,
|
onOpenChange,
|
||||||
initialValue = MIN_VALUE,
|
initialValue = MIN_VALUE,
|
||||||
onSave,
|
onSave,
|
||||||
}: ConfigureMemoryDialogProps) {
|
}: ConfigureMemoryDialogProps): JSX.Element {
|
||||||
const clampedInitial = useMemo(
|
const clampedInitial = useMemo(
|
||||||
() => clampValue(initialValue, MIN_VALUE, MAX_VALUE),
|
() => clampValue(initialValue, MIN_VALUE, MAX_VALUE),
|
||||||
[initialValue]
|
[initialValue]
|
||||||
@ -82,21 +110,35 @@ export function ConfigureMemoryDialog({
|
|||||||
useEscapeKey(() => onOpenChange(false), open);
|
useEscapeKey(() => onOpenChange(false), open);
|
||||||
useBodyScrollLock(open);
|
useBodyScrollLock(open);
|
||||||
|
|
||||||
const handleSave = () => {
|
/**
|
||||||
|
* Handle save action
|
||||||
|
* @description Saves the memory configuration and closes dialog
|
||||||
|
*/
|
||||||
|
const handleSave = (): void => {
|
||||||
if (onSave && memoryValue >= MIN_VALUE && memoryValue <= MAX_VALUE) {
|
if (onSave && memoryValue >= MIN_VALUE && memoryValue <= MAX_VALUE) {
|
||||||
onSave(memoryValue);
|
onSave(memoryValue);
|
||||||
}
|
}
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {
|
/**
|
||||||
|
* Handle keyboard events on save button
|
||||||
|
* @description Handles Enter and Space key presses
|
||||||
|
* @param e - Keyboard event
|
||||||
|
*/
|
||||||
|
const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>): void => {
|
||||||
if (e.key === 'Enter' || e.key === ' ') {
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handleSave();
|
handleSave();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSliderChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
/**
|
||||||
|
* Handle slider value change
|
||||||
|
* @description Updates memory value when slider moves
|
||||||
|
* @param e - Change event from slider input
|
||||||
|
*/
|
||||||
|
const handleSliderChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
setMemoryValue(Number(e.target.value));
|
setMemoryValue(Number(e.target.value));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -6,9 +6,15 @@
|
|||||||
import { X, ArrowRight } from 'lucide-react';
|
import { X, ArrowRight } from 'lucide-react';
|
||||||
import type { Tool } from '@/types';
|
import type { Tool } from '@/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ToolChip component props
|
||||||
|
*/
|
||||||
interface ToolChipProps {
|
interface ToolChipProps {
|
||||||
|
/** Tool object to display */
|
||||||
tool: Tool;
|
tool: Tool;
|
||||||
|
/** Callback when delete button is clicked */
|
||||||
onDelete: (id: string) => void;
|
onDelete: (id: string) => void;
|
||||||
|
/** Callback when redirect button is clicked */
|
||||||
onRedirect: (id: string) => void;
|
onRedirect: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,8 +10,10 @@ import type { Tool } from '@/types';
|
|||||||
/**
|
/**
|
||||||
* Toggle Switch Component
|
* Toggle Switch Component
|
||||||
* @description A toggle switch that visually represents on/off state
|
* @description A toggle switch that visually represents on/off state
|
||||||
|
* @param enabled - Whether the toggle is enabled
|
||||||
|
* @returns {JSX.Element} ToggleSwitch element
|
||||||
*/
|
*/
|
||||||
function ToggleSwitch({ enabled }: { enabled: boolean }) {
|
function ToggleSwitch({ enabled }: { enabled: boolean }): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`relative h-5 w-[35px] rounded-full transition-colors duration-200 ${
|
className={`relative h-5 w-[35px] rounded-full transition-colors duration-200 ${
|
||||||
@ -30,9 +32,9 @@ function ToggleSwitch({ enabled }: { enabled: boolean }) {
|
|||||||
/**
|
/**
|
||||||
* AgentCreatePage component
|
* AgentCreatePage component
|
||||||
* @description Page for creating a new agent with configuration options
|
* @description Page for creating a new agent with configuration options
|
||||||
* @returns Agent creation form page
|
* @returns {JSX.Element} Agent creation form page
|
||||||
*/
|
*/
|
||||||
export function AgentCreatePage() {
|
export function AgentCreatePage(): JSX.Element {
|
||||||
const [enableKb, setEnableKb] = useState(false);
|
const [enableKb, setEnableKb] = useState(false);
|
||||||
const [enableMemory, setEnableMemory] = useState(true);
|
const [enableMemory, setEnableMemory] = useState(true);
|
||||||
const [isToolDialogOpen, setIsToolDialogOpen] = useState(false);
|
const [isToolDialogOpen, setIsToolDialogOpen] = useState(false);
|
||||||
@ -44,27 +46,52 @@ export function AgentCreatePage() {
|
|||||||
{ id: '2', name: 'GitHub', type: 'MCP', color: '#8fbc24' },
|
{ id: '2', name: 'GitHub', type: 'MCP', color: '#8fbc24' },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleAddTool = (toolData: Omit<Tool, 'id'>) => {
|
/**
|
||||||
|
* Handle adding a new tool
|
||||||
|
* @description Adds a new tool to the agent configuration
|
||||||
|
* @param toolData - Tool data without ID
|
||||||
|
*/
|
||||||
|
const handleAddTool = (toolData: Omit<Tool, 'id'>): void => {
|
||||||
const newTool: Tool = {
|
const newTool: Tool = {
|
||||||
...toolData,
|
...toolData,
|
||||||
id: Date.now().toString(), // Simple ID generation
|
id: Date.now().toString(),
|
||||||
};
|
};
|
||||||
setTools((prev) => [...prev, newTool]);
|
setTools((prev) => [...prev, newTool]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUpdateTool = (toolId: string, toolData: Omit<Tool, 'id'>) => {
|
/**
|
||||||
|
* Handle updating an existing tool
|
||||||
|
* @description Updates tool data for the specified tool ID
|
||||||
|
* @param toolId - ID of the tool to update
|
||||||
|
* @param toolData - Updated tool data without ID
|
||||||
|
*/
|
||||||
|
const handleUpdateTool = (
|
||||||
|
toolId: string,
|
||||||
|
toolData: Omit<Tool, 'id'>
|
||||||
|
): void => {
|
||||||
setTools((prev) =>
|
setTools((prev) =>
|
||||||
prev.map((tool) => (tool.id === toolId ? { ...tool, ...toolData } : tool))
|
prev.map((tool) =>
|
||||||
|
tool.id === toolId ? { ...tool, ...toolData } : tool
|
||||||
|
)
|
||||||
);
|
);
|
||||||
setEditingTool(null);
|
setEditingTool(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteTool = (id: string) => {
|
/**
|
||||||
|
* Handle deleting a tool
|
||||||
|
* @description Removes a tool from the agent configuration
|
||||||
|
* @param id - ID of the tool to delete
|
||||||
|
*/
|
||||||
|
const handleDeleteTool = (id: string): void => {
|
||||||
setTools((prev) => prev.filter((tool) => tool.id !== id));
|
setTools((prev) => prev.filter((tool) => tool.id !== id));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRedirectTool = (id: string) => {
|
/**
|
||||||
// Find the tool and open configuration/update dialog
|
* Handle redirecting to tool configuration
|
||||||
|
* @description Opens the tool dialog for editing the specified tool
|
||||||
|
* @param id - ID of the tool to configure
|
||||||
|
*/
|
||||||
|
const handleRedirectTool = (id: string): void => {
|
||||||
const tool = tools.find((t) => t.id === id);
|
const tool = tools.find((t) => t.id === id);
|
||||||
if (tool) {
|
if (tool) {
|
||||||
setEditingTool(tool);
|
setEditingTool(tool);
|
||||||
@ -72,7 +99,12 @@ export function AgentCreatePage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDialogClose = (open: boolean) => {
|
/**
|
||||||
|
* Handle dialog close state change
|
||||||
|
* @description Manages dialog open/close state and resets editing tool
|
||||||
|
* @param open - Whether the dialog should be open
|
||||||
|
*/
|
||||||
|
const handleDialogClose = (open: boolean): void => {
|
||||||
setIsToolDialogOpen(open);
|
setIsToolDialogOpen(open);
|
||||||
if (!open) {
|
if (!open) {
|
||||||
setEditingTool(null);
|
setEditingTool(null);
|
||||||
@ -80,7 +112,7 @@ export function AgentCreatePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen px-[50px] py-6">
|
<div className="min-h-screen px-4 py-6 md:px-8 lg:px-[50px]">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h1 className="font-semibold text-[20px] text-black leading-normal">
|
<h1 className="font-semibold text-[20px] text-black leading-normal">
|
||||||
Add Agent
|
Add Agent
|
||||||
@ -286,7 +318,8 @@ export function AgentCreatePage() {
|
|||||||
src="/Agent/add.svg"
|
src="/Agent/add.svg"
|
||||||
alt="Add"
|
alt="Add"
|
||||||
className="size-3.5 filter brightness-0"
|
className="size-3.5 filter brightness-0"
|
||||||
/> </div>
|
/>
|
||||||
|
</div>
|
||||||
<span className="font-medium text-sm text-black leading-[1.5] text-left">
|
<span className="font-medium text-sm text-black leading-[1.5] text-left">
|
||||||
Add
|
Add
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -1,11 +1,17 @@
|
|||||||
import { Link } from '@tanstack/react-router';
|
import { Link } from '@tanstack/react-router';
|
||||||
import { APP_PATHS } from '@/routes';
|
import { APP_PATHS } from '@/routes';
|
||||||
|
|
||||||
const searchIcon = 'https://www.figma.com/api/mcp/asset/379327bd-47f2-4ebc-a8e0-c0004928d27b';
|
const searchIcon =
|
||||||
|
'https://www.figma.com/api/mcp/asset/379327bd-47f2-4ebc-a8e0-c0004928d27b';
|
||||||
const emptyStateIcon = '/Agent/agent.svg';
|
const emptyStateIcon = '/Agent/agent.svg';
|
||||||
const addIcon = '/Agent/add.svg';
|
const addIcon = '/Agent/add.svg';
|
||||||
|
|
||||||
export function AgentPage() {
|
/**
|
||||||
|
* AgentPage component
|
||||||
|
* @description Displays the agent management page with search and empty state
|
||||||
|
* @returns {JSX.Element} AgentPage element
|
||||||
|
*/
|
||||||
|
export function AgentPage(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="px-4 py-6 md:px-6 md:py-8 lg:px-10 lg:pt-10 lg:pb-16">
|
<div className="px-4 py-6 md:px-6 md:py-8 lg:px-10 lg:pt-10 lg:pb-16">
|
||||||
<div className="flex flex-col gap-6 md:gap-8">
|
<div className="flex flex-col gap-6 md:gap-8">
|
||||||
@ -21,7 +27,11 @@ export function AgentPage() {
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex-1 w-full max-w-2xl">
|
<div className="flex-1 w-full max-w-2xl">
|
||||||
<div className="flex items-center gap-3 rounded-xl border border-[#E1E4EF] bg-white px-3 py-2.5 md:px-4 md:py-3 shadow-sm">
|
<div className="flex items-center gap-3 rounded-xl border border-[#E1E4EF] bg-white px-3 py-2.5 md:px-4 md:py-3 shadow-sm">
|
||||||
<img src={searchIcon} alt="Search" className="h-4 w-4 md:h-5 md:w-5 opacity-70" />
|
<img
|
||||||
|
src={searchIcon}
|
||||||
|
alt="Search"
|
||||||
|
className="h-4 w-4 md:h-5 md:w-5 opacity-70"
|
||||||
|
/>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search Agent"
|
placeholder="Search Agent"
|
||||||
|
|||||||
@ -12,9 +12,9 @@ import { MOCK_AGENTS } from '@/constants/agents';
|
|||||||
/**
|
/**
|
||||||
* Dashboard component
|
* Dashboard component
|
||||||
* @description Main dashboard page with all sections
|
* @description Main dashboard page with all sections
|
||||||
* @returns Dashboard element
|
* @returns {JSX.Element} Dashboard element
|
||||||
*/
|
*/
|
||||||
export function Dashboard() {
|
export function Dashboard(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="px-4 py-4 md:px-6 lg:px-10 lg:pt-6 lg:pb-10">
|
<div className="px-4 py-4 md:px-6 lg:px-10 lg:pt-6 lg:pb-10">
|
||||||
{/* Content Header: Welcome + Search/Create */}
|
{/* Content Header: Welcome + Search/Create */}
|
||||||
|
|||||||
@ -24,41 +24,120 @@ import { AuthFormCard, ForgotPasswordModal } from '@/components/auth';
|
|||||||
export function LoginPage(): JSX.Element {
|
export function LoginPage(): JSX.Element {
|
||||||
const [showForgotPwd, setShowForgotPwd] = useState(false);
|
const [showForgotPwd, setShowForgotPwd] = useState(false);
|
||||||
|
|
||||||
const handleSignIn = (email: string, password: string): void => {
|
/**
|
||||||
console.log('Sign in:', { email, password });
|
* Handle sign in form submission
|
||||||
|
* @description Processes user sign in credentials
|
||||||
|
* @param email - User email address
|
||||||
|
* @param password - User password
|
||||||
|
* @throws {Error} When authentication fails
|
||||||
|
*/
|
||||||
|
const handleSignIn = async (email: string, password: string): Promise<void> => {
|
||||||
|
try {
|
||||||
|
// TODO: Implement actual authentication API call
|
||||||
|
// await signInUser({ email, password });
|
||||||
|
} catch (error) {
|
||||||
|
// Error handling will be implemented with proper logging service
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRegister = (data: {
|
/**
|
||||||
|
* Handle user registration
|
||||||
|
* @description Processes new user registration
|
||||||
|
* @param data - Registration form data
|
||||||
|
* @throws {Error} When registration fails
|
||||||
|
*/
|
||||||
|
const handleRegister = async (data: {
|
||||||
firstName: string;
|
firstName: string;
|
||||||
lastName: string;
|
lastName: string;
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
}): void => {
|
}): Promise<void> => {
|
||||||
console.log('Register:', data);
|
try {
|
||||||
|
// TODO: Implement actual registration API call
|
||||||
|
// await registerUser(data);
|
||||||
|
} catch (error) {
|
||||||
|
// Error handling will be implemented with proper logging service
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGoogleAuth = (): void => {
|
/**
|
||||||
console.log('Google auth clicked');
|
* Handle Google authentication
|
||||||
|
* @description Initiates Google OAuth flow
|
||||||
|
* @throws {Error} When OAuth flow fails
|
||||||
|
*/
|
||||||
|
const handleGoogleAuth = async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
// TODO: Implement Google OAuth integration
|
||||||
|
// await authenticateWithGoogle();
|
||||||
|
} catch (error) {
|
||||||
|
// Error handling will be implemented with proper logging service
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAzureAuth = (): void => {
|
/**
|
||||||
console.log('Azure auth clicked');
|
* Handle Azure authentication
|
||||||
|
* @description Initiates Azure AD authentication flow
|
||||||
|
* @throws {Error} When Azure authentication fails
|
||||||
|
*/
|
||||||
|
const handleAzureAuth = async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
// TODO: Implement Azure AD authentication
|
||||||
|
// await authenticateWithAzure();
|
||||||
|
} catch (error) {
|
||||||
|
// Error handling will be implemented with proper logging service
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle forgot password click
|
||||||
|
* @description Opens the forgot password modal
|
||||||
|
*/
|
||||||
const handleForgotPasswordClick = (): void => {
|
const handleForgotPasswordClick = (): void => {
|
||||||
setShowForgotPwd(true);
|
setShowForgotPwd(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle forgot password modal close
|
||||||
|
* @description Closes the forgot password modal
|
||||||
|
*/
|
||||||
const handleForgotPasswordClose = (): void => {
|
const handleForgotPasswordClose = (): void => {
|
||||||
setShowForgotPwd(false);
|
setShowForgotPwd(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleForgotPasswordSubmit = (email: string): void => {
|
/**
|
||||||
console.log('Password recovery requested for:', email);
|
* Handle forgot password form submission
|
||||||
|
* @description Sends password recovery email
|
||||||
|
* @param email - User email address for password recovery
|
||||||
|
* @throws {Error} When password recovery request fails
|
||||||
|
*/
|
||||||
|
const handleForgotPasswordSubmit = async (email: string): Promise<void> => {
|
||||||
|
try {
|
||||||
|
// TODO: Implement password recovery API call
|
||||||
|
// await requestPasswordRecovery(email);
|
||||||
|
} catch (error) {
|
||||||
|
// Error handling will be implemented with proper logging service
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOtpVerify = (otp: string): void => {
|
/**
|
||||||
console.log('OTP verification:', otp);
|
* Handle OTP verification
|
||||||
|
* @description Verifies the OTP code for password recovery
|
||||||
|
* @param otp - 6-digit OTP code
|
||||||
|
* @throws {Error} When OTP verification fails
|
||||||
|
*/
|
||||||
|
const handleOtpVerify = async (otp: string): Promise<void> => {
|
||||||
|
try {
|
||||||
|
// TODO: Implement OTP verification API call
|
||||||
|
// await verifyOtp(otp);
|
||||||
|
} catch (error) {
|
||||||
|
// Error handling will be implemented with proper logging service
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -84,7 +84,12 @@ const notFoundRoute = createRoute({
|
|||||||
|
|
||||||
const routeTree = rootRoute.addChildren([
|
const routeTree = rootRoute.addChildren([
|
||||||
publicRoute.addChildren([loginRoute, signUpRoute]),
|
publicRoute.addChildren([loginRoute, signUpRoute]),
|
||||||
appRoute.addChildren([dashboardRoute,agentRoute,agentCreateRoute,notFoundRoute]),
|
appRoute.addChildren([
|
||||||
|
dashboardRoute,
|
||||||
|
agentRoute,
|
||||||
|
agentCreateRoute,
|
||||||
|
notFoundRoute,
|
||||||
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const router = createRouter({
|
export const router = createRouter({
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user