{
+ const res = await markChatUnreadById(localStorage.token, id).catch((error) => {
+ toast.error(`${error}`);
+ return null;
+ });
+
+ if (res) {
+ await refreshSidebar();
+ }
+ };
+
const archiveChatHandler = async (id) => {
try {
await archiveChatById(localStorage.token, id);
@@ -818,6 +830,9 @@
renameHandler={() => {
renameHandler(chat.id);
}}
+ markUnreadHandler={() => {
+ markUnreadHandler(chat.id);
+ }}
deleteHandler={() => {
menuChatId = chat.id;
menuChatTitle = chat.title;
diff --git a/src/lib/components/layout/Sidebar.svelte b/src/lib/components/layout/Sidebar.svelte
index d61359a430..16aa3fab7d 100644
--- a/src/lib/components/layout/Sidebar.svelte
+++ b/src/lib/components/layout/Sidebar.svelte
@@ -22,7 +22,7 @@
socket,
config,
isApp,
- models,
+ visiblePinnedModels,
selectedFolder,
WEBUI_NAME,
sidebarWidth
@@ -120,9 +120,7 @@
let showCreateFolderModal = false;
- let pinnedModels = [];
-
- let showPinnedModels = false;
+ let showPinnedModels = true;
let showPinnedNotes = false;
let showChannels = false;
let showFolders = false;
@@ -130,6 +128,7 @@
let showChatsMenu = false;
let folders = {};
+ type SelectedSidebarFolder = { id: string } | null;
let folderRegistry: Record<
string,
{
@@ -145,6 +144,14 @@
let sharedFolders: any[] = [];
+ const initSelectedFolderChats = (folder: SelectedSidebarFolder) => {
+ if (!folder?.id) {
+ return;
+ }
+
+ folderRegistry[folder.id]?.setFolderItems?.();
+ };
+
$: pinnedItems = $settings?.pinnedMenuItems ?? DEFAULT_PINNED_ITEMS;
const isMenuItemVisible = (id) => {
@@ -230,29 +237,33 @@
}
};
- $: if ($selectedFolder) {
- initFolders();
- }
+ $: initSelectedFolderChats($selectedFolder as SelectedSidebarFolder);
const initFolders = async () => {
if ($config?.features?.enable_folders === false) {
return;
}
- const folderList = await getFolders(localStorage.token).catch((error) => {
- return [];
- });
+ const [folderList, sharedFolderList] = await Promise.all([
+ getFolders(localStorage.token).catch((error) => {
+ return [];
+ }),
+ getSharedFolders(localStorage.token).catch((error) => {
+ return [];
+ })
+ ]);
_folders.set(folderList.sort((a, b) => b.updated_at - a.updated_at));
- folders = {};
+ sharedFolders = sharedFolderList;
+ const folderMap: Record = {};
// First pass: Initialize all folder entries
for (const folder of folderList) {
// Ensure folder is added to folders with its data
- folders[folder.id] = { ...(folders[folder.id] || {}), ...folder };
+ folderMap[folder.id] = { ...(folderMap[folder.id] || {}), ...folder };
if (newFolderId && folder.id === newFolderId) {
- folders[folder.id].new = true;
+ folderMap[folder.id].new = true;
newFolderId = null;
}
}
@@ -261,42 +272,38 @@
for (const folder of folderList) {
if (folder.parent_id) {
// Ensure the parent folder is initialized if it doesn't exist
- if (!folders[folder.parent_id]) {
- folders[folder.parent_id] = {}; // Create a placeholder if not already present
+ if (!folderMap[folder.parent_id]) {
+ folderMap[folder.parent_id] = {}; // Create a placeholder if not already present
}
// Initialize childrenIds array if it doesn't exist and add the current folder id
- folders[folder.parent_id].childrenIds = folders[folder.parent_id].childrenIds
- ? [...folders[folder.parent_id].childrenIds, folder.id]
+ folderMap[folder.parent_id].childrenIds = folderMap[folder.parent_id].childrenIds
+ ? [...folderMap[folder.parent_id].childrenIds, folder.id]
: [folder.id];
// Sort the children by updated_at field
- folders[folder.parent_id].childrenIds.sort((a, b) => {
- return folders[b].updated_at - folders[a].updated_at;
+ folderMap[folder.parent_id].childrenIds.sort((a, b) => {
+ return folderMap[b].updated_at - folderMap[a].updated_at;
});
}
}
// Merge shared folders into the same structure
- try {
- sharedFolders = await getSharedFolders(localStorage.token);
- } catch (e) {
- sharedFolders = [];
- }
-
for (const sf of sharedFolders) {
- if (folders[sf.id]) continue; // Already owned by user
- folders[sf.id] = { ...sf, shared: true };
+ if (folderMap[sf.id]) continue; // Already owned by user
+ folderMap[sf.id] = { ...sf, shared: true };
}
// Build parent-child relationships for shared folders
for (const sf of sharedFolders) {
- if (folders[sf.id]?.shared && sf.parent_id && folders[sf.parent_id]) {
- folders[sf.parent_id].childrenIds = folders[sf.parent_id].childrenIds
- ? [...new Set([...folders[sf.parent_id].childrenIds, sf.id])]
+ if (folderMap[sf.id]?.shared && sf.parent_id && folderMap[sf.parent_id]) {
+ folderMap[sf.parent_id].childrenIds = folderMap[sf.parent_id].childrenIds
+ ? [...new Set([...folderMap[sf.parent_id].childrenIds, sf.id])]
: [sf.id];
}
}
+
+ folders = folderMap;
};
const initSharedFolders = async () => {
@@ -674,12 +681,6 @@
navElement.style['-webkit-app-region'] = 'drag';
}
}
- }),
- settings.subscribe((value) => {
- if (pinnedModels != value?.pinnedModels ?? []) {
- pinnedModels = value?.pinnedModels ?? [];
- showPinnedModels = pinnedModels.length > 0;
- }
})
];
@@ -700,7 +701,12 @@
socketInstance?.on('events', chatActiveEventHandler);
socketInstance?.on('connect', refreshChatRows);
- const unregisterFolderRefreshHandler = registerFolderRefreshHandler((folderId, chat) => {
+ const unregisterFolderRefreshHandler = registerFolderRefreshHandler(async (folderId, chat) => {
+ // null refreshes the folder tree; undefined refreshes all folder chat lists.
+ if (folderId === null) {
+ return initFolders();
+ }
+
if (folderId) {
if (chat) {
return folderRegistry[folderId]?.upsertChat?.(chat);
@@ -1177,7 +1183,7 @@
{
if (e.target.scrollTop === 0) {
scrollTop = 0;
@@ -1276,11 +1282,10 @@
- {#if ($models ?? []).length > 0 && (($settings?.pinnedModels ?? []).length > 0 || $config?.default_pinned_models)}
+ {#if $visiblePinnedModels.length > 0}