Show files only when existent

This commit is contained in:
Lucas Oliveira 2025-11-24 17:21:08 -03:00
parent 4f082c536c
commit c068f3a065

View file

@ -1,13 +1,13 @@
"use client"; "use client";
import { import {
EllipsisVertical, EllipsisVertical,
FileText, FileText,
Library, Library,
MessageSquare, MessageSquare,
Plus, Plus,
Settings2, Settings2,
Trash2, Trash2,
} from "lucide-react"; } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
@ -15,10 +15,10 @@ import { useEffect, useRef, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { useDeleteSessionMutation } from "@/app/api/queries/useDeleteSessionMutation"; import { useDeleteSessionMutation } from "@/app/api/queries/useDeleteSessionMutation";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"; } from "@/components/ui/dropdown-menu";
import { type EndpointType, useChat } from "@/contexts/chat-context"; import { type EndpointType, useChat } from "@/contexts/chat-context";
import { useKnowledgeFilter } from "@/contexts/knowledge-filter-context"; import { useKnowledgeFilter } from "@/contexts/knowledge-filter-context";
@ -30,488 +30,484 @@ import { KnowledgeFilterList } from "./knowledge-filter-list";
// Re-export the types for backward compatibility // Re-export the types for backward compatibility
export interface RawConversation { export interface RawConversation {
response_id: string; response_id: string;
title: string; title: string;
endpoint: string; endpoint: string;
messages: Array<{ messages: Array<{
role: string; role: string;
content: string; content: string;
timestamp?: string; timestamp?: string;
response_id?: string; response_id?: string;
}>; }>;
created_at?: string; created_at?: string;
last_activity?: string; last_activity?: string;
previous_response_id?: string; previous_response_id?: string;
total_messages: number; total_messages: number;
[key: string]: unknown; [key: string]: unknown;
} }
export interface ChatConversation { export interface ChatConversation {
response_id: string; response_id: string;
title: string; title: string;
endpoint: EndpointType; endpoint: EndpointType;
messages: Array<{ messages: Array<{
role: string; role: string;
content: string; content: string;
timestamp?: string; timestamp?: string;
response_id?: string; response_id?: string;
}>; }>;
created_at?: string; created_at?: string;
last_activity?: string; last_activity?: string;
previous_response_id?: string; previous_response_id?: string;
total_messages: number; total_messages: number;
[key: string]: unknown; [key: string]: unknown;
} }
interface NavigationProps { interface NavigationProps {
conversations?: ChatConversation[]; conversations?: ChatConversation[];
isConversationsLoading?: boolean; isConversationsLoading?: boolean;
onNewConversation?: () => void; onNewConversation?: () => void;
} }
export function Navigation({ export function Navigation({
conversations = [], conversations = [],
isConversationsLoading = false, isConversationsLoading = false,
onNewConversation, onNewConversation,
}: NavigationProps = {}) { }: NavigationProps = {}) {
const pathname = usePathname(); const pathname = usePathname();
const { const {
endpoint, endpoint,
loadConversation, loadConversation,
currentConversationId, currentConversationId,
setCurrentConversationId, setCurrentConversationId,
startNewConversation, startNewConversation,
conversationDocs, conversationDocs,
conversationData, conversationData,
refreshConversations, refreshConversations,
placeholderConversation, placeholderConversation,
setPlaceholderConversation, setPlaceholderConversation,
conversationLoaded, conversationLoaded,
} = useChat(); } = useChat();
const { loading } = useLoadingStore(); const { loading } = useLoadingStore();
const [previousConversationCount, setPreviousConversationCount] = useState(0); const [previousConversationCount, setPreviousConversationCount] = useState(0);
const [deleteModalOpen, setDeleteModalOpen] = useState(false); const [deleteModalOpen, setDeleteModalOpen] = useState(false);
const [conversationToDelete, setConversationToDelete] = const [conversationToDelete, setConversationToDelete] =
useState<ChatConversation | null>(null); useState<ChatConversation | null>(null);
const hasCompletedInitialLoad = useRef(false); const hasCompletedInitialLoad = useRef(false);
const mountTimeRef = useRef<number | null>(null); const mountTimeRef = useRef<number | null>(null);
const { selectedFilter, setSelectedFilter } = useKnowledgeFilter(); const { selectedFilter, setSelectedFilter } = useKnowledgeFilter();
// Delete session mutation // Delete session mutation
const deleteSessionMutation = useDeleteSessionMutation({ const deleteSessionMutation = useDeleteSessionMutation({
onSuccess: () => { onSuccess: () => {
toast.success("Conversation deleted successfully"); toast.success("Conversation deleted successfully");
// If we deleted the current conversation, select another one // If we deleted the current conversation, select another one
if ( if (
conversationToDelete && conversationToDelete &&
currentConversationId === conversationToDelete.response_id currentConversationId === conversationToDelete.response_id
) { ) {
// Filter out the deleted conversation and find the next one // Filter out the deleted conversation and find the next one
const remainingConversations = conversations.filter( const remainingConversations = conversations.filter(
(conv) => conv.response_id !== conversationToDelete.response_id, (conv) => conv.response_id !== conversationToDelete.response_id,
); );
if (remainingConversations.length > 0) { if (remainingConversations.length > 0) {
// Load the first available conversation (most recent) // Load the first available conversation (most recent)
loadConversation(remainingConversations[0]); loadConversation(remainingConversations[0]);
} else { } else {
// No conversations left, start a new one // No conversations left, start a new one
setCurrentConversationId(null); setCurrentConversationId(null);
if (onNewConversation) { if (onNewConversation) {
onNewConversation(); onNewConversation();
} else { } else {
refreshConversations(); refreshConversations();
startNewConversation(); startNewConversation();
} }
} }
} }
setDeleteModalOpen(false); setDeleteModalOpen(false);
setConversationToDelete(null); setConversationToDelete(null);
}, },
onError: (error) => { onError: (error) => {
toast.error(`Failed to delete conversation: ${error.message}`); toast.error(`Failed to delete conversation: ${error.message}`);
}, },
}); });
const handleNewConversation = () => { const handleNewConversation = () => {
// Use the prop callback if provided, otherwise use the context method // Use the prop callback if provided, otherwise use the context method
if (onNewConversation) { if (onNewConversation) {
onNewConversation(); onNewConversation();
} else { } else {
refreshConversations(); refreshConversations();
startNewConversation(); startNewConversation();
} }
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("newConversation")); window.dispatchEvent(new CustomEvent("newConversation"));
} }
}; };
const handleDeleteConversation = ( const handleDeleteConversation = (
conversation: ChatConversation, conversation: ChatConversation,
event?: React.MouseEvent, event?: React.MouseEvent,
) => { ) => {
if (event) { if (event) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
} }
setConversationToDelete(conversation); setConversationToDelete(conversation);
setDeleteModalOpen(true); setDeleteModalOpen(true);
}; };
const handleContextMenuAction = ( const handleContextMenuAction = (
action: string, action: string,
conversation: ChatConversation, conversation: ChatConversation,
) => { ) => {
switch (action) { switch (action) {
case "delete": case "delete":
handleDeleteConversation(conversation); handleDeleteConversation(conversation);
break; break;
// Add more actions here in the future (rename, duplicate, etc.) // Add more actions here in the future (rename, duplicate, etc.)
default: default:
break; break;
} }
}; };
const confirmDeleteConversation = () => { const confirmDeleteConversation = () => {
if (conversationToDelete) { if (conversationToDelete) {
deleteSessionMutation.mutate({ deleteSessionMutation.mutate({
sessionId: conversationToDelete.response_id, sessionId: conversationToDelete.response_id,
endpoint: endpoint, endpoint: endpoint,
}); });
} }
}; };
const routes = [ const routes = [
{ {
label: "Chat", label: "Chat",
icon: MessageSquare, icon: MessageSquare,
href: "/chat", href: "/chat",
active: pathname === "/" || pathname.startsWith("/chat"), active: pathname === "/" || pathname.startsWith("/chat"),
}, },
{ {
label: "Knowledge", label: "Knowledge",
icon: Library, icon: Library,
href: "/knowledge", href: "/knowledge",
active: pathname.startsWith("/knowledge"), active: pathname.startsWith("/knowledge"),
}, },
{ {
label: "Settings", label: "Settings",
icon: Settings2, icon: Settings2,
href: "/settings", href: "/settings",
active: pathname.startsWith("/settings"), active: pathname.startsWith("/settings"),
}, },
]; ];
const isOnChatPage = pathname === "/" || pathname === "/chat"; const isOnChatPage = pathname === "/" || pathname === "/chat";
const isOnKnowledgePage = pathname.startsWith("/knowledge"); const isOnKnowledgePage = pathname.startsWith("/knowledge");
// Track mount time to prevent auto-selection right after component mounts (e.g., after onboarding) // Track mount time to prevent auto-selection right after component mounts (e.g., after onboarding)
useEffect(() => { useEffect(() => {
if (mountTimeRef.current === null) { if (mountTimeRef.current === null) {
mountTimeRef.current = Date.now(); mountTimeRef.current = Date.now();
} }
}, []); }, []);
// Track when initial load completes // Track when initial load completes
useEffect(() => { useEffect(() => {
if (!isConversationsLoading && !hasCompletedInitialLoad.current) { if (!isConversationsLoading && !hasCompletedInitialLoad.current) {
hasCompletedInitialLoad.current = true; hasCompletedInitialLoad.current = true;
// Set initial count after first load completes // Set initial count after first load completes
setPreviousConversationCount(conversations.length); setPreviousConversationCount(conversations.length);
} }
}, [isConversationsLoading, conversations.length]); }, [isConversationsLoading, conversations.length]);
// Clear placeholder when conversation count increases (new conversation was created) // Clear placeholder when conversation count increases (new conversation was created)
useEffect(() => { useEffect(() => {
const currentCount = conversations.length; const currentCount = conversations.length;
const timeSinceMount = mountTimeRef.current const timeSinceMount = mountTimeRef.current
? Date.now() - mountTimeRef.current ? Date.now() - mountTimeRef.current
: Infinity; : Infinity;
const MIN_TIME_AFTER_MOUNT = 2000; // 2 seconds - prevents selection right after onboarding const MIN_TIME_AFTER_MOUNT = 2000; // 2 seconds - prevents selection right after onboarding
// Only select if: // Only select if:
// 1. We have a placeholder (new conversation was created) // 1. We have a placeholder (new conversation was created)
// 2. Initial load has completed (prevents selection on browser refresh) // 2. Initial load has completed (prevents selection on browser refresh)
// 3. Count increased (new conversation appeared) // 3. Count increased (new conversation appeared)
// 4. Not currently loading // 4. Not currently loading
// 5. Enough time has passed since mount (prevents selection after onboarding completes) // 5. Enough time has passed since mount (prevents selection after onboarding completes)
if ( if (
placeholderConversation && placeholderConversation &&
hasCompletedInitialLoad.current && hasCompletedInitialLoad.current &&
currentCount > previousConversationCount && currentCount > previousConversationCount &&
conversations.length > 0 && conversations.length > 0 &&
!isConversationsLoading && !isConversationsLoading &&
timeSinceMount >= MIN_TIME_AFTER_MOUNT timeSinceMount >= MIN_TIME_AFTER_MOUNT
) { ) {
setPlaceholderConversation(null); setPlaceholderConversation(null);
// Highlight the most recent conversation (first in sorted array) without loading its messages // Highlight the most recent conversation (first in sorted array) without loading its messages
const newestConversation = conversations[0]; const newestConversation = conversations[0];
if (newestConversation) { if (newestConversation) {
setCurrentConversationId(newestConversation.response_id); setCurrentConversationId(newestConversation.response_id);
} }
} }
// Update the previous count only after initial load // Update the previous count only after initial load
if (hasCompletedInitialLoad.current) { if (hasCompletedInitialLoad.current) {
setPreviousConversationCount(currentCount); setPreviousConversationCount(currentCount);
} }
}, [ }, [
conversations.length, conversations.length,
placeholderConversation, placeholderConversation,
setPlaceholderConversation, setPlaceholderConversation,
previousConversationCount, previousConversationCount,
conversations, conversations,
setCurrentConversationId, setCurrentConversationId,
isConversationsLoading, isConversationsLoading,
]); ]);
useEffect(() => { useEffect(() => {
let activeConvo; let activeConvo;
if (currentConversationId && conversations.length > 0) { if (currentConversationId && conversations.length > 0) {
activeConvo = conversations.find( activeConvo = conversations.find(
(conv) => conv.response_id === currentConversationId, (conv) => conv.response_id === currentConversationId,
); );
} }
if (isOnChatPage && !isConversationsLoading) { if (isOnChatPage && !isConversationsLoading) {
if (conversations.length === 0 && !placeholderConversation) { if (conversations.length === 0 && !placeholderConversation) {
handleNewConversation(); handleNewConversation();
} else if (activeConvo) { } else if (activeConvo) {
loadConversation(activeConvo); loadConversation(activeConvo);
refreshConversations(); refreshConversations();
} else if ( } else if (
conversations.length > 0 && conversations.length > 0 &&
currentConversationId === null && currentConversationId === null &&
!placeholderConversation !placeholderConversation
) { ) {
handleNewConversation(); handleNewConversation();
} }
} }
}, [isOnChatPage, conversations, conversationLoaded]); }, [isOnChatPage, conversations, conversationLoaded]);
const newConversationFiles = conversationData?.messages const newConversationFiles = conversationData?.messages
.filter( .filter(
(message) => (message) =>
message.role === "user" && message.role === "user" &&
(message.content.match(FILES_REGEX)?.[0] ?? null) !== null, (message.content.match(FILES_REGEX)?.[0] ?? null) !== null,
) )
.map((message) => message.content.match(FILES_REGEX)?.[0] ?? null) .map((message) => message.content.match(FILES_REGEX)?.[0] ?? null)
.concat(conversationDocs.map((doc) => doc.filename)); .concat(conversationDocs.map((doc) => doc.filename));
return ( return (
<div className="flex flex-col h-full bg-background"> <div className="flex flex-col h-full bg-background">
<div className="px-4 py-2 flex-shrink-0"> <div className="px-4 py-2 flex-shrink-0">
<div className="space-y-1"> <div className="space-y-1">
{routes.map((route) => ( {routes.map((route) => (
<div key={route.href}> <div key={route.href}>
<Link <Link
href={route.href} href={route.href}
className={cn( className={cn(
"text-[13px] group flex p-3 w-full justify-start font-medium cursor-pointer hover:bg-accent hover:text-accent-foreground rounded-lg transition-all", "text-[13px] group flex p-3 w-full justify-start font-medium cursor-pointer hover:bg-accent hover:text-accent-foreground rounded-lg transition-all",
route.active route.active
? "bg-accent text-accent-foreground shadow-sm" ? "bg-accent text-accent-foreground shadow-sm"
: "text-foreground hover:text-accent-foreground", : "text-foreground hover:text-accent-foreground",
)} )}
> >
<div className="flex items-center flex-1"> <div className="flex items-center flex-1">
<route.icon <route.icon
className={cn( className={cn(
"h-[18px] w-[18px] mr-2 shrink-0", "h-[18px] w-[18px] mr-2 shrink-0",
route.active route.active
? "text-muted-foreground" ? "text-muted-foreground"
: "text-muted-foreground group-hover:text-muted-foreground", : "text-muted-foreground group-hover:text-muted-foreground",
)} )}
/> />
{route.label} {route.label}
</div> </div>
</Link> </Link>
{route.label === "Settings" && ( {route.label === "Settings" && (
<div className="my-2 border-t border-border" /> <div className="my-2 border-t border-border" />
)} )}
</div> </div>
))} ))}
</div> </div>
</div> </div>
{isOnKnowledgePage && ( {isOnKnowledgePage && (
<KnowledgeFilterList <KnowledgeFilterList
selectedFilter={selectedFilter} selectedFilter={selectedFilter}
onFilterSelect={setSelectedFilter} onFilterSelect={setSelectedFilter}
/> />
)} )}
{/* Chat Page Specific Sections */} {/* Chat Page Specific Sections */}
{isOnChatPage && ( {isOnChatPage && (
<div className="flex-1 min-h-0 flex flex-col px-4"> <div className="flex-1 min-h-0 flex flex-col px-4">
{/* Conversations Section */} {/* Conversations Section */}
<div className="flex-shrink-0"> <div className="flex-shrink-0">
<div className="flex items-center justify-between mb-3 mx-3"> <div className="flex items-center justify-between mb-3 mx-3">
<h3 className="text-xs font-medium text-muted-foreground"> <h3 className="text-xs font-medium text-muted-foreground">
Conversations Conversations
</h3> </h3>
<button <button
type="button" type="button"
className="p-1 hover:bg-accent rounded" className="p-1 hover:bg-accent rounded"
onClick={handleNewConversation} onClick={handleNewConversation}
title="Start new conversation" title="Start new conversation"
disabled={loading} disabled={loading}
> >
<Plus className="h-4 w-4 text-muted-foreground" /> <Plus className="h-4 w-4 text-muted-foreground" />
</button> </button>
</div> </div>
</div> </div>
<div className="flex-1 min-h-0 overflow-y-auto scrollbar-hide"> <div className="flex-1 min-h-0 overflow-y-auto scrollbar-hide">
<div className="space-y-1 flex flex-col"> <div className="space-y-1 flex flex-col">
{/* Show skeleton loaders when loading and no conversations exist */} {/* Show skeleton loaders when loading and no conversations exist */}
{isConversationsLoading && conversations.length === 0 ? ( {isConversationsLoading && conversations.length === 0 ? (
[0, 1].map((skeletonIndex) => ( [0, 1].map((skeletonIndex) => (
<div <div
key={`conversation-skeleton-${skeletonIndex}`} key={`conversation-skeleton-${skeletonIndex}`}
className={cn( className={cn(
"w-full px-3 h-11 rounded-lg animate-pulse", "w-full px-3 h-11 rounded-lg animate-pulse",
skeletonIndex === 0 ? "bg-accent/50" : "", skeletonIndex === 0 ? "bg-accent/50" : "",
)} )}
> >
<div className="h-3 bg-muted-foreground/20 rounded w-3/4 mt-3.5" /> <div className="h-3 bg-muted-foreground/20 rounded w-3/4 mt-3.5" />
</div> </div>
)) ))
) : ( ) : (
<> <>
{/* Show regular conversations */} {/* Show regular conversations */}
{conversations.length === 0 && !isConversationsLoading ? ( {conversations.length === 0 && !isConversationsLoading ? (
<div className="text-[13px] text-muted-foreground py-2 pl-3"> <div className="text-[13px] text-muted-foreground py-2 pl-3">
No conversations yet No conversations yet
</div> </div>
) : ( ) : (
conversations.map((conversation) => ( conversations.map((conversation) => (
<button <button
key={conversation.response_id} key={conversation.response_id}
type="button" type="button"
className={`w-full px-3 h-11 rounded-lg group relative text-left ${ className={`w-full px-3 h-11 rounded-lg group relative text-left ${
loading || isConversationsLoading loading || isConversationsLoading
? "opacity-50 cursor-not-allowed" ? "opacity-50 cursor-not-allowed"
: "hover:bg-accent cursor-pointer" : "hover:bg-accent cursor-pointer"
} ${ } ${
currentConversationId === conversation.response_id currentConversationId === conversation.response_id
? "bg-accent" ? "bg-accent"
: "" : ""
}`} }`}
onClick={() => { onClick={() => {
if (loading || isConversationsLoading) return; if (loading || isConversationsLoading) return;
loadConversation(conversation); loadConversation(conversation);
refreshConversations(); refreshConversations();
}} }}
disabled={loading || isConversationsLoading} disabled={loading || isConversationsLoading}
> >
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="text-sm font-medium text-foreground truncate"> <div className="text-sm font-medium text-foreground truncate">
{conversation.title} {conversation.title}
</div> </div>
</div> </div>
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger <DropdownMenuTrigger
disabled={ disabled={
loading || loading ||
isConversationsLoading || isConversationsLoading ||
deleteSessionMutation.isPending deleteSessionMutation.isPending
} }
asChild asChild
> >
<div <div
className="opacity-0 group-hover:opacity-100 data-[state=open]:opacity-100 data-[state=open]:text-foreground transition-opacity p-1 hover:bg-accent rounded text-muted-foreground hover:text-foreground ml-2 flex-shrink-0 cursor-pointer" className="opacity-0 group-hover:opacity-100 data-[state=open]:opacity-100 data-[state=open]:text-foreground transition-opacity p-1 hover:bg-accent rounded text-muted-foreground hover:text-foreground ml-2 flex-shrink-0 cursor-pointer"
title="More options" title="More options"
role="button" role="button"
tabIndex={0} tabIndex={0}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
}} }}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") { if (e.key === "Enter" || e.key === " ") {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
} }
}} }}
> >
<EllipsisVertical className="h-4 w-4" /> <EllipsisVertical className="h-4 w-4" />
</div> </div>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent <DropdownMenuContent
side="bottom" side="bottom"
align="end" align="end"
className="w-48" className="w-48"
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<DropdownMenuItem <DropdownMenuItem
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
handleContextMenuAction( handleContextMenuAction(
"delete", "delete",
conversation, conversation,
); );
}} }}
className="cursor-pointer text-destructive focus:text-destructive" className="cursor-pointer text-destructive focus:text-destructive"
> >
<Trash2 className="mr-2 h-4 w-4" /> <Trash2 className="mr-2 h-4 w-4" />
Delete conversation Delete conversation
</DropdownMenuItem> </DropdownMenuItem>
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
</div> </div>
</button> </button>
)) ))
)} )}
</> </>
)} )}
</div> </div>
<div className="flex-shrink-0 mt-4"> {(newConversationFiles?.length ?? 0) !== 0 && (
<div className="flex items-center justify-between mb-3 mx-3"> <div className="flex-shrink-0 mt-4">
<h3 className="text-xs font-medium text-muted-foreground"> <div className="flex items-center justify-between mb-3 mx-3">
Files <h3 className="text-xs font-medium text-muted-foreground">
</h3> Files
</div> </h3>
<div className="overflow-y-auto scrollbar-hide space-y-1"> </div>
{(newConversationFiles?.length ?? 0) === 0 ? ( <div className="overflow-y-auto scrollbar-hide space-y-1">
<div className="text-[13px] text-muted-foreground py-2 px-3"> {newConversationFiles?.map((file, index) => (
No documents yet <div
</div> key={`${file}-${index}`}
) : ( className="flex-1 min-w-0 px-3"
newConversationFiles?.map((file, index) => ( >
<div <div className="text-mmd font-medium text-foreground truncate">
key={`${file}-${index}`} {file}
className="flex-1 min-w-0 px-3" </div>
> </div>
<div className="text-mmd font-medium text-foreground truncate"> ))}
{file} </div>
</div> </div>
</div> )}
)) </div>
)} </div>
</div> )}
</div>
</div>
</div>
)}
{/* Delete Session Modal */} {/* Delete Session Modal */}
<DeleteSessionModal <DeleteSessionModal
isOpen={deleteModalOpen} isOpen={deleteModalOpen}
onClose={() => { onClose={() => {
setDeleteModalOpen(false); setDeleteModalOpen(false);
setConversationToDelete(null); setConversationToDelete(null);
}} }}
onConfirm={confirmDeleteConversation} onConfirm={confirmDeleteConversation}
sessionTitle={conversationToDelete?.title || ""} sessionTitle={conversationToDelete?.title || ""}
isDeleting={deleteSessionMutation.isPending} isDeleting={deleteSessionMutation.isPending}
/> />
</div> </div>
); );
} }