mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-10 20:35:17 +02:00
refactor: implement chat tab removal functionality and enhance tab title update logic for improved user experience
This commit is contained in:
parent
7632291731
commit
b54aa517a8
4 changed files with 59 additions and 4 deletions
|
|
@ -128,6 +128,21 @@ export const updateChatTabTitleAtom = atom(
|
|||
(get, set, { chatId, title }: { chatId: number; title: string }) => {
|
||||
const state = get(tabsStateAtom);
|
||||
const tabId = makeChatTabId(chatId);
|
||||
const hasExactTab = state.tabs.some((t) => t.id === tabId);
|
||||
|
||||
// During lazy thread creation, title updates can arrive before "chat-new"
|
||||
// is swapped to chat-{id}. In that case, promote the active "chat-new" tab.
|
||||
if (!hasExactTab && state.activeTabId === "chat-new") {
|
||||
set(tabsStateAtom, {
|
||||
...state,
|
||||
activeTabId: tabId,
|
||||
tabs: state.tabs.map((t) =>
|
||||
t.id === "chat-new" ? { ...t, id: tabId, chatId, title } : t
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
set(tabsStateAtom, {
|
||||
...state,
|
||||
tabs: state.tabs.map((t) => (t.id === tabId ? { ...t, title } : t)),
|
||||
|
|
@ -213,6 +228,34 @@ export const closeTabAtom = atom(null, (get, set, tabId: string) => {
|
|||
return remaining.find((t) => t.id === newActiveId) ?? null;
|
||||
});
|
||||
|
||||
/** Remove a chat tab by chat ID (used when a chat is deleted). */
|
||||
export const removeChatTabAtom = atom(null, (get, set, chatId: number) => {
|
||||
const state = get(tabsStateAtom);
|
||||
const tabId = makeChatTabId(chatId);
|
||||
const idx = state.tabs.findIndex((t) => t.id === tabId);
|
||||
if (idx === -1) return null;
|
||||
|
||||
const remaining = state.tabs.filter((t) => t.id !== tabId);
|
||||
|
||||
// Always keep at least one tab available.
|
||||
if (remaining.length === 0) {
|
||||
set(tabsStateAtom, {
|
||||
tabs: [INITIAL_CHAT_TAB],
|
||||
activeTabId: "chat-new",
|
||||
});
|
||||
return INITIAL_CHAT_TAB;
|
||||
}
|
||||
|
||||
let newActiveId = state.activeTabId;
|
||||
if (state.activeTabId === tabId) {
|
||||
const newIdx = Math.min(idx, remaining.length - 1);
|
||||
newActiveId = remaining[newIdx].id;
|
||||
}
|
||||
|
||||
set(tabsStateAtom, { tabs: remaining, activeTabId: newActiveId });
|
||||
return remaining.find((t) => t.id === newActiveId) ?? null;
|
||||
});
|
||||
|
||||
/** Reset tabs when switching search spaces. */
|
||||
export const resetTabsAtom = atom(null, (_get, set) => {
|
||||
set(tabsStateAtom, { ...initialState });
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import {
|
|||
teamDialogAtom,
|
||||
userSettingsDialogAtom,
|
||||
} from "@/atoms/settings/settings-dialog.atoms";
|
||||
import { resetTabsAtom, syncChatTabAtom, type Tab } from "@/atoms/tabs/tabs.atom";
|
||||
import { removeChatTabAtom, resetTabsAtom, syncChatTabAtom, type Tab } from "@/atoms/tabs/tabs.atom";
|
||||
import { currentUserAtom } from "@/atoms/user/user-query.atoms";
|
||||
import { MorePagesDialog } from "@/components/settings/more-pages-dialog";
|
||||
import { SearchSpaceSettingsDialog } from "@/components/settings/search-space-settings-dialog";
|
||||
|
|
@ -103,6 +103,7 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid
|
|||
const resetCurrentThread = useSetAtom(resetCurrentThreadAtom);
|
||||
const syncChatTab = useSetAtom(syncChatTabAtom);
|
||||
const resetTabs = useSetAtom(resetTabsAtom);
|
||||
const removeChatTab = useSetAtom(removeChatTabAtom);
|
||||
|
||||
// State for handling new chat navigation when router is out of sync
|
||||
const [pendingNewChat, setPendingNewChat] = useState(false);
|
||||
|
|
@ -325,7 +326,8 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid
|
|||
const thread = threadsData?.threads?.find((t) => t.id === chatId);
|
||||
syncChatTab({
|
||||
chatId,
|
||||
title: thread?.title || (chatId ? `Chat ${chatId}` : "New Chat"),
|
||||
// Avoid overwriting live SSE-updated tab titles with fallback values.
|
||||
title: chatId ? (thread?.title ?? undefined) : "New Chat",
|
||||
chatUrl,
|
||||
});
|
||||
}, [currentChatId, searchSpaceId, threadsData?.threads, syncChatTab]);
|
||||
|
|
@ -637,6 +639,7 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid
|
|||
setIsDeletingChat(true);
|
||||
try {
|
||||
await deleteThread(chatToDelete.id);
|
||||
removeChatTab(chatToDelete.id);
|
||||
queryClient.invalidateQueries({ queryKey: ["threads", searchSpaceId] });
|
||||
if (currentChatId === chatToDelete.id) {
|
||||
resetCurrentThread();
|
||||
|
|
@ -664,6 +667,7 @@ export function LayoutDataProvider({ searchSpaceId, children }: LayoutDataProvid
|
|||
currentThreadState.id,
|
||||
params?.chat_id,
|
||||
router,
|
||||
removeChatTab,
|
||||
]);
|
||||
|
||||
// Rename handler
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { format } from "date-fns";
|
||||
import {
|
||||
ArchiveIcon,
|
||||
|
|
@ -41,6 +42,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
|
|||
import { useDebouncedValue } from "@/hooks/use-debounced-value";
|
||||
import { useLongPress } from "@/hooks/use-long-press";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { removeChatTabAtom } from "@/atoms/tabs/tabs.atom";
|
||||
import {
|
||||
deleteThread,
|
||||
fetchThreads,
|
||||
|
|
@ -70,6 +72,7 @@ export function AllPrivateChatsSidebarContent({
|
|||
const params = useParams();
|
||||
const queryClient = useQueryClient();
|
||||
const isMobile = useIsMobile();
|
||||
const removeChatTab = useSetAtom(removeChatTabAtom);
|
||||
|
||||
const currentChatId = Array.isArray(params.chat_id)
|
||||
? Number(params.chat_id[0])
|
||||
|
|
@ -158,6 +161,7 @@ export function AllPrivateChatsSidebarContent({
|
|||
setDeletingThreadId(threadId);
|
||||
try {
|
||||
await deleteThread(threadId);
|
||||
removeChatTab(threadId);
|
||||
toast.success(t("chat_deleted") || "Chat deleted successfully");
|
||||
queryClient.invalidateQueries({ queryKey: ["all-threads", searchSpaceId] });
|
||||
queryClient.invalidateQueries({ queryKey: ["search-threads", searchSpaceId] });
|
||||
|
|
@ -176,7 +180,7 @@ export function AllPrivateChatsSidebarContent({
|
|||
setDeletingThreadId(null);
|
||||
}
|
||||
},
|
||||
[queryClient, searchSpaceId, t, currentChatId, router, onOpenChange]
|
||||
[queryClient, searchSpaceId, t, currentChatId, router, onOpenChange, removeChatTab]
|
||||
);
|
||||
|
||||
const handleToggleArchive = useCallback(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useSetAtom } from "jotai";
|
||||
import { format } from "date-fns";
|
||||
import {
|
||||
ArchiveIcon,
|
||||
|
|
@ -41,6 +42,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip
|
|||
import { useDebouncedValue } from "@/hooks/use-debounced-value";
|
||||
import { useLongPress } from "@/hooks/use-long-press";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { removeChatTabAtom } from "@/atoms/tabs/tabs.atom";
|
||||
import {
|
||||
deleteThread,
|
||||
fetchThreads,
|
||||
|
|
@ -70,6 +72,7 @@ export function AllSharedChatsSidebarContent({
|
|||
const params = useParams();
|
||||
const queryClient = useQueryClient();
|
||||
const isMobile = useIsMobile();
|
||||
const removeChatTab = useSetAtom(removeChatTabAtom);
|
||||
|
||||
const currentChatId = Array.isArray(params.chat_id)
|
||||
? Number(params.chat_id[0])
|
||||
|
|
@ -158,6 +161,7 @@ export function AllSharedChatsSidebarContent({
|
|||
setDeletingThreadId(threadId);
|
||||
try {
|
||||
await deleteThread(threadId);
|
||||
removeChatTab(threadId);
|
||||
toast.success(t("chat_deleted") || "Chat deleted successfully");
|
||||
queryClient.invalidateQueries({ queryKey: ["all-threads", searchSpaceId] });
|
||||
queryClient.invalidateQueries({ queryKey: ["search-threads", searchSpaceId] });
|
||||
|
|
@ -176,7 +180,7 @@ export function AllSharedChatsSidebarContent({
|
|||
setDeletingThreadId(null);
|
||||
}
|
||||
},
|
||||
[queryClient, searchSpaceId, t, currentChatId, router, onOpenChange]
|
||||
[queryClient, searchSpaceId, t, currentChatId, router, onOpenChange, removeChatTab]
|
||||
);
|
||||
|
||||
const handleToggleArchive = useCallback(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue