refac
This commit is contained in:
1 parent
ba7c95f7ef
commit
e5a08d5220
6 files changed
+106
-1
No files matched your search
@@ -694,6 +694,21 @@ class ChatTable:
|
|||||||
await session.commit()
|
await session.commit()
|
||||||
return result.rowcount or 0
|
return result.rowcount or 0
|
||||||
|
|
||||||
|
async def mark_root_chats_read_by_user_id(self, user_id: str, db: AsyncSession | None = None) -> int:
|
||||||
|
async with get_async_db_context(db) as session:
|
||||||
|
result = await session.execute(
|
||||||
|
update(Chat)
|
||||||
|
.where(
|
||||||
|
Chat.user_id == user_id,
|
||||||
|
Chat.folder_id.is_(None),
|
||||||
|
Chat.archived == False,
|
||||||
|
Chat.meta['internal'].as_boolean().is_not(True),
|
||||||
|
)
|
||||||
|
.values(last_read_at=Chat.updated_at)
|
||||||
|
)
|
||||||
|
await session.commit()
|
||||||
|
return result.rowcount or 0
|
||||||
|
|
||||||
async def update_chat_title_by_id(self, id: str, title: str) -> ChatModel | None:
|
async def update_chat_title_by_id(self, id: str, title: str) -> ChatModel | None:
|
||||||
try:
|
try:
|
||||||
async with get_async_db_context() as session:
|
async with get_async_db_context() as session:
|
||||||
|
|||||||
@@ -255,6 +255,14 @@ async def get_session_user_chat_list(
|
|||||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT())
|
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT())
|
||||||
|
|
||||||
|
|
||||||
|
@router.post('/read')
|
||||||
|
async def mark_root_chats_read_by_user_id(
|
||||||
|
user=Depends(get_verified_user),
|
||||||
|
db: AsyncSession = Depends(get_async_session),
|
||||||
|
):
|
||||||
|
return {'updated_count': await Chats.mark_root_chats_read_by_user_id(user.id, db=db)}
|
||||||
|
|
||||||
|
|
||||||
############################
|
############################
|
||||||
# GetChatUsageStats
|
# GetChatUsageStats
|
||||||
# EXPERIMENTAL: may be removed in future releases
|
# EXPERIMENTAL: may be removed in future releases
|
||||||
|
|||||||
@@ -913,6 +913,34 @@ export const markChatUnreadById = async (token: string, id: string) => {
|
|||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const markChatsRead = async (token: string) => {
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
const res = await fetch(`${WEBUI_API_BASE_URL}/chats/read`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(token && { authorization: `Bearer ${token}` })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
if (!res.ok) throw await res.json();
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
error = 'detail' in err ? err.detail : err;
|
||||||
|
console.error(err);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
export const cloneChatById = async (token: string, id: string, title?: string) => {
|
export const cloneChatById = async (token: string, id: string, title?: string) => {
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
loadNextChatListPage,
|
loadNextChatListPage,
|
||||||
refreshChatList,
|
refreshChatList,
|
||||||
registerFolderRefreshHandler,
|
registerFolderRefreshHandler,
|
||||||
|
setAllChatsRead,
|
||||||
setChatActive,
|
setChatActive,
|
||||||
setChatReadAt
|
setChatReadAt
|
||||||
} from '$lib/stores/chatList';
|
} from '$lib/stores/chatList';
|
||||||
@@ -47,7 +48,8 @@
|
|||||||
updateChatFolderIdById,
|
updateChatFolderIdById,
|
||||||
importChats,
|
importChats,
|
||||||
deleteAllChats,
|
deleteAllChats,
|
||||||
getChatListBySearchText
|
getChatListBySearchText,
|
||||||
|
markChatsRead
|
||||||
} from '$lib/apis/chats';
|
} from '$lib/apis/chats';
|
||||||
import {
|
import {
|
||||||
createNewFolder,
|
createNewFolder,
|
||||||
@@ -86,6 +88,10 @@
|
|||||||
import WorkspaceIcon from './Sidebar/icons/Workspace.svelte';
|
import WorkspaceIcon from './Sidebar/icons/Workspace.svelte';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
import HotkeyHint from '../common/HotkeyHint.svelte';
|
import HotkeyHint from '../common/HotkeyHint.svelte';
|
||||||
|
import Dropdown from '../common/Dropdown.svelte';
|
||||||
|
import DropdownMenu from '../common/DropdownMenu.svelte';
|
||||||
|
import CheckIcon from '../icons/Check.svelte';
|
||||||
|
import MoreHorizontalIcon from './Sidebar/icons/MoreHorizontal.svelte';
|
||||||
|
|
||||||
const BREAKPOINT = 768;
|
const BREAKPOINT = 768;
|
||||||
const DEFAULT_PINNED_ITEMS = ['notes', 'workspace'];
|
const DEFAULT_PINNED_ITEMS = ['notes', 'workspace'];
|
||||||
@@ -121,6 +127,7 @@
|
|||||||
let showChannels = false;
|
let showChannels = false;
|
||||||
let showFolders = false;
|
let showFolders = false;
|
||||||
let showSharedFolders = false;
|
let showSharedFolders = false;
|
||||||
|
let showChatsMenu = false;
|
||||||
|
|
||||||
let folders = {};
|
let folders = {};
|
||||||
let folderRegistry: Record<
|
let folderRegistry: Record<
|
||||||
@@ -440,6 +447,17 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const markAllChatsReadHandler = async () => {
|
||||||
|
const res = await markChatsRead(localStorage.token).catch((error) => {
|
||||||
|
toast.error(`${error}`);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
if (!res) return;
|
||||||
|
|
||||||
|
showChatsMenu = false;
|
||||||
|
setAllChatsRead();
|
||||||
|
};
|
||||||
|
|
||||||
const importChatHandler = async (items, pinned = false, folderId = null) => {
|
const importChatHandler = async (items, pinned = false, folderId = null) => {
|
||||||
if (!canImportChats) {
|
if (!canImportChats) {
|
||||||
toast.error($i18n.t('Access prohibited'));
|
toast.error($i18n.t('Access prohibited'));
|
||||||
@@ -1434,6 +1452,33 @@
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<svelte:fragment slot="action">
|
||||||
|
<Dropdown bind:show={showChatsMenu} align="end">
|
||||||
|
<Tooltip content={$i18n.t('More')}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="flex items-center justify-center w-7 h-7 rounded-lg text-gray-300 hover:text-gray-500 dark:text-gray-600 dark:hover:text-gray-400 transition-colors duration-100"
|
||||||
|
aria-label={$i18n.t('More')}
|
||||||
|
on:pointerup|stopPropagation
|
||||||
|
>
|
||||||
|
<MoreHorizontalIcon className="size-3.5" strokeWidth="2" />
|
||||||
|
</button>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<div slot="content">
|
||||||
|
<DropdownMenu className="min-w-[170px]">
|
||||||
|
<button
|
||||||
|
class="flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] select-none cursor-pointer hover:bg-gray-50/40 dark:hover:bg-gray-800/40"
|
||||||
|
on:click={markAllChatsReadHandler}
|
||||||
|
>
|
||||||
|
<CheckIcon className="size-3.5" />
|
||||||
|
<div class="flex items-center">{$i18n.t('Mark all as read')}</div>
|
||||||
|
</button>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
</svelte:fragment>
|
||||||
|
|
||||||
{#if $pinnedChats.length > 0}
|
{#if $pinnedChats.length > 0}
|
||||||
<div class="mb-1">
|
<div class="mb-1">
|
||||||
<div class="flex flex-col space-y-1 rounded-xl">
|
<div class="flex flex-col space-y-1 rounded-xl">
|
||||||
|
|||||||
@@ -143,6 +143,8 @@
|
|||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<slot name="action" />
|
||||||
|
|
||||||
{#if onAdd}
|
{#if onAdd}
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -138,6 +138,13 @@ export const setChatReadAt = (chatId: string, lastReadAt: number): boolean => {
|
|||||||
return found;
|
return found;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setAllChatsRead = () => {
|
||||||
|
const updateChat = (chat: ChatListItem) => ({ ...chat, last_read_at: chat.updated_at });
|
||||||
|
|
||||||
|
chatsStore.update((items) => (items ? items.map(updateChat) : items));
|
||||||
|
pinnedChatsStore.update((items) => items.map(updateChat));
|
||||||
|
};
|
||||||
|
|
||||||
export const resetChatListState = () => {
|
export const resetChatListState = () => {
|
||||||
requestGeneration += 1;
|
requestGeneration += 1;
|
||||||
currentPage = 1;
|
currentPage = 1;
|
||||||
|
|||||||
Reference in new issue
Block a user