diff --git a/surfsense_web/components/layout/ui/sidebar/InboxSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/InboxSidebar.tsx index 810e3a22e..eacae6e49 100644 --- a/surfsense_web/components/layout/ui/sidebar/InboxSidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/InboxSidebar.tsx @@ -7,6 +7,7 @@ import { Check, CheckCheck, CheckCircle2, + Copy, History, Inbox, LayoutGrid, @@ -43,6 +44,8 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip import { getConnectorIcon } from "@/contracts/enums/connectorIcons"; import { type ConnectorIndexingMetadata, + isChatClonedMetadata, + isChatCloneFailedMetadata, isConnectorIndexingMetadata, isNewMentionMetadata, type NewMentionMetadata, @@ -196,10 +199,15 @@ export function InboxSidebar({ [inboxItems] ); + // Status tab includes: connector indexing, document processing, chat clone notifications const statusItems = useMemo( () => inboxItems.filter( - (item) => item.type === "connector_indexing" || item.type === "document_processing" + (item) => + item.type === "connector_indexing" || + item.type === "document_processing" || + item.type === "chat_cloned" || + item.type === "chat_clone_failed" ), [inboxItems] ); @@ -320,7 +328,17 @@ export function InboxSidebar({ router.push(url); } } + } else if (item.type === "chat_cloned") { + // Navigate to the cloned chat + if (isChatClonedMetadata(item.metadata)) { + const { search_space_id, thread_id } = item.metadata; + const url = `/dashboard/${search_space_id}/new-chat/${thread_id}`; + onOpenChange(false); + onCloseMobileSidebar?.(); + router.push(url); + } } + // chat_clone_failed: just mark as read, no navigation }, [markAsRead, router, onOpenChange, onCloseMobileSidebar] ); @@ -380,6 +398,24 @@ export function InboxSidebar({ ); } + // For chat cloned success, show green copy icon + if (item.type === "chat_cloned") { + return ( +
+ +
+ ); + } + + // For chat clone failed, show red alert icon + if (item.type === "chat_clone_failed") { + return ( +
+ +
+ ); + } + // For status items (connector/document), show status icons // Safely access status from metadata const metadata = item.metadata as Record; diff --git a/surfsense_web/components/public-chat/public-chat-footer.tsx b/surfsense_web/components/public-chat/public-chat-footer.tsx index 80779b4e6..cc54d4150 100644 --- a/surfsense_web/components/public-chat/public-chat-footer.tsx +++ b/surfsense_web/components/public-chat/public-chat-footer.tsx @@ -26,6 +26,9 @@ export function PublicChatFooter({ shareToken }: PublicChatFooterProps) { share_token: shareToken, }); + // Force PGlite to resync notifications on next dashboard load + localStorage.setItem("surfsense_force_notif_resync", "true"); + toast.success("Copying chat to your account...", { description: "You'll be notified when it's ready.", }); diff --git a/surfsense_web/lib/electric/client.ts b/surfsense_web/lib/electric/client.ts index 148da58ec..4e7ff87e7 100644 --- a/surfsense_web/lib/electric/client.ts +++ b/surfsense_web/lib/electric/client.ts @@ -274,6 +274,16 @@ export async function initElectric(userId: string): Promise { CREATE INDEX IF NOT EXISTS idx_new_chat_messages_created_at ON new_chat_messages(created_at); `); + // Force resync notifications if flagged (e.g., after clone from public page) + if ( + typeof window !== "undefined" && + localStorage.getItem("surfsense_force_notif_resync") === "true" + ) { + console.log("[Electric] Force resync flag detected, clearing notifications table"); + await db.exec("DELETE FROM notifications"); + localStorage.removeItem("surfsense_force_notif_resync"); + } + const electricUrl = getElectricUrl(); // STEP 4: Create the client wrapper