mirror of https://github.com/kortix-ai/suna.git
chore(ui): make agent selector simpler
This commit is contained in:
parent
23fa2ba4e8
commit
06b0035b51
|
@ -209,7 +209,7 @@ export function DashboardContent() {
|
||||||
<h1 className="tracking-tight text-4xl text-muted-foreground leading-tight">
|
<h1 className="tracking-tight text-4xl text-muted-foreground leading-tight">
|
||||||
Hey, I am
|
Hey, I am
|
||||||
</h1>
|
</h1>
|
||||||
<h1 className="tracking-tight text-4xl font-semibold leading-tight text-primary">
|
<h1 className="ml-1 tracking-tight text-4xl font-semibold leading-tight text-primary">
|
||||||
{displayName}
|
{displayName}
|
||||||
{agentAvatar && (
|
{agentAvatar && (
|
||||||
<span className="text-muted-foreground ml-2">
|
<span className="text-muted-foreground ml-2">
|
||||||
|
|
|
@ -1,28 +1,25 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { Settings, ChevronRight, Bot, Presentation, Video, Code, FileSpreadsheet, Search, Plus, Star, User, Sparkles, Database, MessageSquare, Calculator, Palette, Zap } from 'lucide-react';
|
import { Settings, ChevronRight, Bot, Presentation, FileSpreadsheet, Search, Plus, User, Check, ChevronDown } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
Popover,
|
DropdownMenu,
|
||||||
PopoverContent,
|
DropdownMenuContent,
|
||||||
PopoverTrigger,
|
DropdownMenuItem,
|
||||||
} from '@/components/ui/popover';
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Separator } from '@/components/ui/separator';
|
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipProvider,
|
TooltipProvider,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from '@/components/ui/tooltip';
|
} from '@/components/ui/tooltip';
|
||||||
import { ChatSettingsDialog } from './chat-settings-dialog';
|
|
||||||
import { SubscriptionStatus } from './_use-model-selection';
|
|
||||||
import { useAgents } from '@/hooks/react-query/agents/use-agents';
|
import { useAgents } from '@/hooks/react-query/agents/use-agents';
|
||||||
import { useFeatureFlag } from '@/lib/feature-flags';
|
import { ChatSettingsDialog } from './chat-settings-dialog';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { Label } from '@/components/ui/label';
|
|
||||||
|
|
||||||
interface PredefinedAgent {
|
interface PredefinedAgent {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -35,16 +32,16 @@ interface PredefinedAgent {
|
||||||
const PREDEFINED_AGENTS: PredefinedAgent[] = [
|
const PREDEFINED_AGENTS: PredefinedAgent[] = [
|
||||||
{
|
{
|
||||||
id: 'slides',
|
id: 'slides',
|
||||||
name: 'Slides Pro',
|
name: 'Slides',
|
||||||
description: 'Create stunning presentations and slide decks',
|
description: 'Create stunning presentations and slide decks',
|
||||||
icon: <Presentation className="h-4 w-4 mt-1" />,
|
icon: <Presentation className="h-4 w-4" />,
|
||||||
category: 'productivity'
|
category: 'productivity'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'sheets',
|
id: 'sheets',
|
||||||
name: 'Data Analyst',
|
name: 'Sheets',
|
||||||
description: 'Spreadsheet and data analysis expert',
|
description: 'Spreadsheet and data analysis expert',
|
||||||
icon: <FileSpreadsheet className="h-4 w-4 mt-1" />,
|
icon: <FileSpreadsheet className="h-4 w-4" />,
|
||||||
category: 'productivity'
|
category: 'productivity'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -55,14 +52,13 @@ interface ChatSettingsDropdownProps {
|
||||||
selectedModel: string;
|
selectedModel: string;
|
||||||
onModelChange: (model: string) => void;
|
onModelChange: (model: string) => void;
|
||||||
modelOptions: any[];
|
modelOptions: any[];
|
||||||
subscriptionStatus: SubscriptionStatus;
|
subscriptionStatus: any;
|
||||||
canAccessModel: (modelId: string) => boolean;
|
canAccessModel: (modelId: string) => boolean;
|
||||||
refreshCustomModels?: () => void;
|
refreshCustomModels?: () => void;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
className?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ChatSettingsDropdown({
|
export const ChatSettingsDropdown: React.FC<ChatSettingsDropdownProps> = ({
|
||||||
selectedAgentId,
|
selectedAgentId,
|
||||||
onAgentSelect,
|
onAgentSelect,
|
||||||
selectedModel,
|
selectedModel,
|
||||||
|
@ -72,202 +68,220 @@ export function ChatSettingsDropdown({
|
||||||
canAccessModel,
|
canAccessModel,
|
||||||
refreshCustomModels,
|
refreshCustomModels,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
className,
|
}) => {
|
||||||
}: ChatSettingsDropdownProps) {
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
|
const [highlightedIndex, setHighlightedIndex] = useState<number>(-1);
|
||||||
const [dialogOpen, setDialogOpen] = useState(false);
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
// Check if custom agents feature is enabled
|
const { data: agentsResponse, isLoading: agentsLoading } = useAgents();
|
||||||
const { enabled: customAgentsEnabled, loading: flagsLoading } = useFeatureFlag('custom_agents');
|
const agents = agentsResponse?.agents || [];
|
||||||
|
|
||||||
// Fetch real agents from API only if feature is enabled
|
// Combine all agents
|
||||||
const { data: agentsResponse, isLoading: agentsLoading, refetch: loadAgents } = useAgents({
|
const allAgents = [
|
||||||
limit: 100,
|
{
|
||||||
sort_by: 'name',
|
id: undefined,
|
||||||
sort_order: 'asc'
|
name: 'Suna',
|
||||||
});
|
description: 'Your personal AI assistant',
|
||||||
|
type: 'default' as const,
|
||||||
|
icon: <User className="h-4 w-4" />
|
||||||
|
},
|
||||||
|
...PREDEFINED_AGENTS.map(agent => ({
|
||||||
|
...agent,
|
||||||
|
type: 'predefined' as const
|
||||||
|
})),
|
||||||
|
...agents.map((agent: any) => ({
|
||||||
|
...agent,
|
||||||
|
id: agent.agent_id,
|
||||||
|
type: 'custom' as const,
|
||||||
|
icon: agent.avatar || <Bot className="h-4 w-4" />
|
||||||
|
}))
|
||||||
|
];
|
||||||
|
|
||||||
const agents = (customAgentsEnabled && agentsResponse?.agents) || [];
|
// Filter agents based on search query
|
||||||
const defaultAgent = agents.find(agent => agent.is_default);
|
const filteredAgents = allAgents.filter((agent) =>
|
||||||
|
agent.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
|
agent.description?.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
// Find selected agent - could be from real agents or predefined
|
useEffect(() => {
|
||||||
const selectedRealAgent = agents.find(a => a.agent_id === selectedAgentId);
|
if (isOpen && searchInputRef.current) {
|
||||||
const selectedPredefinedAgent = PREDEFINED_AGENTS.find(a => a.id === selectedAgentId);
|
setTimeout(() => {
|
||||||
const selectedAgent = selectedRealAgent || selectedPredefinedAgent;
|
searchInputRef.current?.focus();
|
||||||
|
}, 50);
|
||||||
const handleAgentSelect = (agentId: string | undefined) => {
|
} else {
|
||||||
onAgentSelect?.(agentId);
|
setSearchQuery('');
|
||||||
setDropdownOpen(false);
|
setHighlightedIndex(-1);
|
||||||
};
|
}
|
||||||
|
}, [isOpen]);
|
||||||
const handleMoreOptions = () => {
|
|
||||||
setDropdownOpen(false);
|
|
||||||
setDialogOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleExploreAll = () => {
|
|
||||||
setDropdownOpen(false);
|
|
||||||
router.push('/agents');
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAgentDisplay = () => {
|
const getAgentDisplay = () => {
|
||||||
if (selectedRealAgent) {
|
const selectedAgent = allAgents.find(agent => agent.id === selectedAgentId);
|
||||||
|
if (selectedAgent) {
|
||||||
return {
|
return {
|
||||||
name: selectedRealAgent.name,
|
name: selectedAgent.name,
|
||||||
icon: <Bot className="h-4 w-4" />,
|
icon: selectedAgent.icon
|
||||||
avatar: selectedRealAgent.avatar
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (selectedPredefinedAgent) {
|
|
||||||
return {
|
|
||||||
name: selectedPredefinedAgent.name,
|
|
||||||
icon: selectedPredefinedAgent.icon,
|
|
||||||
avatar: null
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
name: 'Suna',
|
name: 'Suna',
|
||||||
icon: <User className="h-4 w-4" />,
|
icon: <User className="h-4 w-4" />
|
||||||
avatar: null
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAgentSelect = (agentId: string | undefined) => {
|
||||||
|
onAgentSelect?.(agentId);
|
||||||
|
setIsOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearchInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (e.key === 'ArrowDown') {
|
||||||
|
e.preventDefault();
|
||||||
|
setHighlightedIndex((prev) =>
|
||||||
|
prev < filteredAgents.length - 1 ? prev + 1 : 0
|
||||||
|
);
|
||||||
|
} else if (e.key === 'ArrowUp') {
|
||||||
|
e.preventDefault();
|
||||||
|
setHighlightedIndex((prev) =>
|
||||||
|
prev > 0 ? prev - 1 : filteredAgents.length - 1
|
||||||
|
);
|
||||||
|
} else if (e.key === 'Enter' && highlightedIndex >= 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
const selectedAgent = filteredAgents[highlightedIndex];
|
||||||
|
if (selectedAgent) {
|
||||||
|
handleAgentSelect(selectedAgent.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleExploreAll = () => {
|
||||||
|
setIsOpen(false);
|
||||||
|
router.push('/agents');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMoreOptions = () => {
|
||||||
|
setIsOpen(false);
|
||||||
|
setDialogOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
const agentDisplay = getAgentDisplay();
|
const agentDisplay = getAgentDisplay();
|
||||||
|
|
||||||
const AgentCard = ({ agent, isSelected, onClick, type }: {
|
|
||||||
agent: any;
|
|
||||||
isSelected: boolean;
|
|
||||||
onClick: () => void;
|
|
||||||
type: 'predefined' | 'custom' | 'default';
|
|
||||||
}) => (
|
|
||||||
<div
|
|
||||||
onClick={onClick}
|
|
||||||
className={cn(
|
|
||||||
"group relative rounded-lg p-1.5 cursor-pointer transition-all",
|
|
||||||
"hover:bg-accent/50",
|
|
||||||
isSelected ? "bg-accent border-accent-foreground/50" : ""
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div className="flex items-start gap-2">
|
|
||||||
<div className="flex-shrink-0">
|
|
||||||
{type === 'default' ? (
|
|
||||||
<User className="h-4 w-4 mt-1" />
|
|
||||||
) : type === 'custom' ? (
|
|
||||||
agent.avatar
|
|
||||||
) : (
|
|
||||||
agent.icon
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="flex-1 min-w-0">
|
|
||||||
<span className="font-medium text-sm truncate">{agent.name}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Popover open={dropdownOpen} onOpenChange={setDropdownOpen}>
|
<DropdownMenu open={isOpen} onOpenChange={setIsOpen}>
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<PopoverTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
className={cn(
|
className="h-8 px-2 text-xs font-medium"
|
||||||
'h-8 w-8 p-0 text-muted-foreground hover:text-foreground relative',
|
|
||||||
'rounded-lg',
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<Settings className="h-4 w-4" />
|
<div className="flex items-center gap-1.5">
|
||||||
{selectedAgentId && (
|
{agentDisplay.icon}
|
||||||
<div className="absolute -top-1 -right-1 h-2 w-2 rounded-full bg-primary" />
|
<span className="hidden sm:inline-block truncate max-w-[80px]">
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
</PopoverTrigger>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent side="top">
|
|
||||||
<p>
|
|
||||||
{agentDisplay.name}
|
{agentDisplay.name}
|
||||||
{agentDisplay.avatar && ` ${agentDisplay.avatar}`}
|
</span>
|
||||||
</p>
|
<ChevronDown className="h-3 w-3 opacity-50" />
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p>Select Agent</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
|
||||||
<PopoverContent align="end" className="w-[480px] p-0" sideOffset={4}>
|
<DropdownMenuContent align="end" className="w-80 p-0" sideOffset={4}>
|
||||||
<div className="p-4">
|
<div className="p-3 border-b">
|
||||||
<div className="mb-4">
|
<div className="relative">
|
||||||
<h3 className="text-sm font-medium">Choose Your Agent</h3>
|
<Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||||
</div>
|
<input
|
||||||
|
ref={searchInputRef}
|
||||||
<div className="grid grid-cols-2 gap-4">
|
type="text"
|
||||||
<div className="space-y-1">
|
placeholder="Search agents..."
|
||||||
<div className="flex items-center gap-2 mb-2">
|
value={searchQuery}
|
||||||
<Label className="text-xs text-muted-foreground font-medium">Default Agents</Label>
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
</div>
|
onKeyDown={handleSearchInputKeyDown}
|
||||||
<AgentCard
|
className="w-full pl-8 pr-3 py-2 text-sm bg-transparent border border-input rounded-md focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
|
||||||
agent={{ name: 'Suna', description: 'Your personal AI assistant' }}
|
|
||||||
isSelected={!selectedAgentId}
|
|
||||||
onClick={() => handleAgentSelect(undefined)}
|
|
||||||
type="default"
|
|
||||||
/>
|
/>
|
||||||
<div className="space-y-1 max-h-[300px] overflow-y-auto">
|
|
||||||
{PREDEFINED_AGENTS.map((agent) => (
|
|
||||||
<AgentCard
|
|
||||||
key={agent.id}
|
|
||||||
agent={agent}
|
|
||||||
isSelected={selectedAgentId === agent.id}
|
|
||||||
onClick={() => handleAgentSelect(agent.id)}
|
|
||||||
type="predefined"
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-3">
|
<div className="max-h-80 overflow-y-auto">
|
||||||
<div className="flex items-center gap-2 mb-2">
|
|
||||||
<Label className="text-xs text-muted-foreground font-medium">Your Agents</Label>
|
|
||||||
</div>
|
|
||||||
{agentsLoading ? (
|
{agentsLoading ? (
|
||||||
<div className="flex items-center justify-center py-8 text-sm text-muted-foreground">
|
<div className="p-3 text-sm text-muted-foreground text-center">
|
||||||
Loading...
|
Loading agents...
|
||||||
</div>
|
</div>
|
||||||
) : agents.length > 0 ? (
|
) : filteredAgents.length === 0 ? (
|
||||||
<div className="space-y-1 max-h-[300px] overflow-y-auto">
|
<div className="p-3 text-sm text-muted-foreground text-center">
|
||||||
{agents.map((agent) => (
|
No agents found
|
||||||
<AgentCard
|
|
||||||
key={agent.agent_id}
|
|
||||||
agent={agent}
|
|
||||||
isSelected={selectedAgentId === agent.agent_id}
|
|
||||||
onClick={() => handleAgentSelect(agent.agent_id)}
|
|
||||||
type="custom"
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col items-center justify-center py-8 text-center">
|
filteredAgents.map((agent, index) => {
|
||||||
<Bot className="h-8 w-8 text-muted-foreground/50 mb-2" />
|
const isSelected = agent.id === selectedAgentId;
|
||||||
<p className="text-sm text-muted-foreground mb-2">No custom agents yet</p>
|
const isHighlighted = index === highlightedIndex;
|
||||||
<Button
|
|
||||||
variant="outline"
|
return (
|
||||||
size="sm"
|
<TooltipProvider key={agent.id || 'default'}>
|
||||||
onClick={handleExploreAll}
|
<Tooltip>
|
||||||
className="text-xs"
|
<TooltipTrigger asChild>
|
||||||
|
<div className="w-full">
|
||||||
|
<DropdownMenuItem
|
||||||
|
className={cn(
|
||||||
|
"text-sm px-3 py-3 mx-2 my-0.5 flex items-center justify-between cursor-pointer",
|
||||||
|
isHighlighted && "bg-accent",
|
||||||
|
)}
|
||||||
|
onClick={() => handleAgentSelect(agent.id)}
|
||||||
|
onMouseEnter={() => setHighlightedIndex(index)}
|
||||||
>
|
>
|
||||||
<Plus className="h-3 w-3 mr-1" />
|
<div className="flex items-center gap-3">
|
||||||
Get Started
|
<div className="flex-shrink-0">
|
||||||
</Button>
|
{agent.icon}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="font-medium text-sm truncate">
|
||||||
|
{agent.name}
|
||||||
|
</span>
|
||||||
|
{agent.type === 'predefined' && (
|
||||||
|
<Badge variant="secondary" className="text-xs px-1 py-0 h-4">
|
||||||
|
Pro
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
{agent.type === 'custom' && (
|
||||||
|
<Badge variant="outline" className="text-xs px-1 py-0 h-4">
|
||||||
|
Custom
|
||||||
|
</Badge>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-xs text-muted-foreground line-clamp-1 mt-0.5">
|
||||||
|
{agent.description}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Separator className="my-4" />
|
</div>
|
||||||
|
{isSelected && (
|
||||||
|
<Check className="h-4 w-4 text-blue-500 flex-shrink-0" />
|
||||||
|
)}
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</div>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent side="left" className="text-xs max-w-xs">
|
||||||
|
<p>{agent.description}</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="border-t p-3">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex gap-2">
|
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
@ -277,22 +291,22 @@ export function ChatSettingsDropdown({
|
||||||
<Search className="h-3 w-3" />
|
<Search className="h-3 w-3" />
|
||||||
Explore All
|
Explore All
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="outline"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={handleMoreOptions}
|
onClick={handleMoreOptions}
|
||||||
className="text-xs"
|
className="text-xs"
|
||||||
>
|
>
|
||||||
<Settings className="h-3 w-3" />
|
<Settings className="h-3 w-3" />
|
||||||
More Options
|
More Options
|
||||||
<ChevronRight className="h-3 w-3" />
|
<ChevronRight className="h-3 w-3 ml-1" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PopoverContent>
|
</DropdownMenuContent>
|
||||||
</Popover>
|
</DropdownMenu>
|
||||||
|
|
||||||
<ChatSettingsDialog
|
<ChatSettingsDialog
|
||||||
open={dialogOpen}
|
open={dialogOpen}
|
||||||
onOpenChange={setDialogOpen}
|
onOpenChange={setDialogOpen}
|
||||||
|
@ -305,4 +319,4 @@ export function ChatSettingsDropdown({
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
Loading…
Reference in New Issue