This commit is contained in:
Timothy Jaeryang Baek 2024-12-22 17:16:14 -07:00
parent 2914c29ab3
commit eaecd15e69
2 changed files with 130 additions and 124 deletions

View File

@ -53,6 +53,7 @@
import { getChannels, createNewChannel } from '$lib/apis/channels'; import { getChannels, createNewChannel } from '$lib/apis/channels';
import CreateChannelModal from './Sidebar/CreateChannelModal.svelte'; import CreateChannelModal from './Sidebar/CreateChannelModal.svelte';
import ChannelItem from './Sidebar/ChannelItem.svelte'; import ChannelItem from './Sidebar/ChannelItem.svelte';
import PencilSquare from '../icons/PencilSquare.svelte';
const BREAKPOINT = 768; const BREAKPOINT = 768;
@ -433,36 +434,6 @@
: 'invisible'}" : 'invisible'}"
> >
<div class="px-1.5 flex justify-between space-x-1 text-gray-600 dark:text-gray-400"> <div class="px-1.5 flex justify-between space-x-1 text-gray-600 dark:text-gray-400">
<a
id="sidebar-new-chat-button"
class="flex flex-1 rounded-lg px-2 py-1 h-full hover:bg-gray-100 dark:hover:bg-gray-900 transition"
href="/"
draggable="false"
on:click={async () => {
selectedChatId = null;
await goto('/');
const newChatButton = document.getElementById('new-chat-button');
setTimeout(() => {
newChatButton?.click();
if ($mobile) {
showSidebar.set(false);
}
}, 0);
}}
>
<div class="self-center mx-1.5">
<img
crossorigin="anonymous"
src="{WEBUI_BASE_URL}/static/favicon.png"
class=" size-5 -translate-x-1.5 rounded-full"
alt="logo"
/>
</div>
<div class=" self-center font-medium text-sm text-gray-850 dark:text-white font-primary">
{$i18n.t('New Chat')}
</div>
</a>
<button <button
class=" cursor-pointer p-[7px] flex rounded-xl hover:bg-gray-100 dark:hover:bg-gray-900 transition" class=" cursor-pointer p-[7px] flex rounded-xl hover:bg-gray-100 dark:hover:bg-gray-900 transition"
on:click={() => { on:click={() => {
@ -486,6 +457,42 @@
</svg> </svg>
</div> </div>
</button> </button>
<a
id="sidebar-new-chat-button"
class="flex justify-between items-center flex-1 rounded-lg px-2 py-1 h-full text-right hover:bg-gray-100 dark:hover:bg-gray-900 transition"
href="/"
draggable="false"
on:click={async () => {
selectedChatId = null;
await goto('/');
const newChatButton = document.getElementById('new-chat-button');
setTimeout(() => {
newChatButton?.click();
if ($mobile) {
showSidebar.set(false);
}
}, 0);
}}
>
<div class="flex items-center">
<div class="self-center mx-1.5">
<img
crossorigin="anonymous"
src="{WEBUI_BASE_URL}/static/favicon.png"
class=" size-5 -translate-x-1.5 rounded-full"
alt="logo"
/>
</div>
<div class=" self-center font-medium text-sm text-gray-850 dark:text-white font-primary">
{$i18n.t('New Chat')}
</div>
</div>
<div>
<PencilSquare className=" size-5" strokeWidth="2" />
</div>
</a>
</div> </div>
{#if $user?.role === 'admin' || $user?.permissions?.workspace?.models || $user?.permissions?.workspace?.knowledge || $user?.permissions?.workspace?.prompts || $user?.permissions?.workspace?.tools} {#if $user?.role === 'admin' || $user?.permissions?.workspace?.models || $user?.permissions?.workspace?.knowledge || $user?.permissions?.workspace?.prompts || $user?.permissions?.workspace?.tools}
@ -544,6 +551,82 @@
? 'opacity-20' ? 'opacity-20'
: ''}" : ''}"
> >
{#if !search && $pinnedChats.length > 0}
<div class="flex flex-col space-y-1 rounded-xl">
<Folder
className="px-2"
bind:open={showPinnedChat}
on:change={(e) => {
localStorage.setItem('showPinnedChat', e.detail);
console.log(e.detail);
}}
on:import={(e) => {
importChatHandler(e.detail, true);
}}
on:drop={async (e) => {
const { type, id, item } = e.detail;
if (type === 'chat') {
let chat = await getChatById(localStorage.token, id).catch((error) => {
return null;
});
if (!chat && item) {
chat = await importChat(localStorage.token, item.chat, item?.meta ?? {});
}
if (chat) {
console.log(chat);
if (chat.folder_id) {
const res = await updateChatFolderIdById(
localStorage.token,
chat.id,
null
).catch((error) => {
toast.error(error);
return null;
});
}
if (!chat.pinned) {
const res = await toggleChatPinnedStatusById(localStorage.token, chat.id);
}
initChatList();
}
}
}}
name={$i18n.t('Pinned')}
>
<div
class="ml-3 pl-1 mt-[1px] flex flex-col overflow-y-auto scrollbar-hidden border-s border-gray-100 dark:border-gray-900"
>
{#each $pinnedChats as chat, idx}
<ChatItem
className=""
id={chat.id}
title={chat.title}
{shiftKey}
selected={selectedChatId === chat.id}
on:select={() => {
selectedChatId = chat.id;
}}
on:unselect={() => {
selectedChatId = null;
}}
on:change={async () => {
initChatList();
}}
on:tag={(e) => {
const { type, name } = e.detail;
tagEventHandler(type, name, chat.id);
}}
/>
{/each}
</div>
</Folder>
</div>
{/if}
{#if ($user.role === 'admin' || $channels.length > 0) && !search} {#if ($user.role === 'admin' || $channels.length > 0) && !search}
<Folder <Folder
className="px-2 mt-0.5" className="px-2 mt-0.5"
@ -562,12 +645,26 @@
</Folder> </Folder>
{/if} {/if}
{#if !search && folders}
<Folders
{folders}
on:import={(e) => {
const { folderId, items } = e.detail;
importChatHandler(items, false, folderId);
}}
on:update={async (e) => {
initChatList();
}}
on:change={async () => {
initChatList();
}}
/>
{/if}
<Folder <Folder
collapsible={!search} collapsible={!search}
className="px-2 mt-0.5" className="px-2 mt-0.5"
name={$i18n.t('Chats')} name={$i18n.t('Chats')}
onAdd={createFolder}
onAddLabel={$i18n.t('New Folder')}
on:import={(e) => { on:import={(e) => {
importChatHandler(e.detail); importChatHandler(e.detail);
}} }}
@ -621,99 +718,7 @@
<div class="absolute z-40 w-full h-full flex justify-center"></div> <div class="absolute z-40 w-full h-full flex justify-center"></div>
{/if} {/if}
{#if !search && $pinnedChats.length > 0}
<div class="flex flex-col space-y-1 rounded-xl">
<Folder
className=""
bind:open={showPinnedChat}
on:change={(e) => {
localStorage.setItem('showPinnedChat', e.detail);
console.log(e.detail);
}}
on:import={(e) => {
importChatHandler(e.detail, true);
}}
on:drop={async (e) => {
const { type, id, item } = e.detail;
if (type === 'chat') {
let chat = await getChatById(localStorage.token, id).catch((error) => {
return null;
});
if (!chat && item) {
chat = await importChat(localStorage.token, item.chat, item?.meta ?? {});
}
if (chat) {
console.log(chat);
if (chat.folder_id) {
const res = await updateChatFolderIdById(
localStorage.token,
chat.id,
null
).catch((error) => {
toast.error(error);
return null;
});
}
if (!chat.pinned) {
const res = await toggleChatPinnedStatusById(localStorage.token, chat.id);
}
initChatList();
}
}
}}
name={$i18n.t('Pinned')}
>
<div
class="ml-3 pl-1 mt-[1px] flex flex-col overflow-y-auto scrollbar-hidden border-s border-gray-100 dark:border-gray-900"
>
{#each $pinnedChats as chat, idx}
<ChatItem
className=""
id={chat.id}
title={chat.title}
{shiftKey}
selected={selectedChatId === chat.id}
on:select={() => {
selectedChatId = chat.id;
}}
on:unselect={() => {
selectedChatId = null;
}}
on:change={async () => {
initChatList();
}}
on:tag={(e) => {
const { type, name } = e.detail;
tagEventHandler(type, name, chat.id);
}}
/>
{/each}
</div>
</Folder>
</div>
{/if}
<div class=" flex-1 flex flex-col overflow-y-auto scrollbar-hidden"> <div class=" flex-1 flex flex-col overflow-y-auto scrollbar-hidden">
{#if !search && folders}
<Folders
{folders}
on:import={(e) => {
const { folderId, items } = e.detail;
importChatHandler(items, false, folderId);
}}
on:update={async (e) => {
initChatList();
}}
on:change={async () => {
initChatList();
}}
/>
{/if}
<div class="pt-1.5"> <div class="pt-1.5">
{#if $chats} {#if $chats}
{#each $chats as chat, idx} {#each $chats as chat, idx}

View File

@ -19,6 +19,7 @@
{#each folderList as folderId (folderId)} {#each folderList as folderId (folderId)}
<RecursiveFolder <RecursiveFolder
className="px-2"
{folders} {folders}
{folderId} {folderId}
on:import={(e) => { on:import={(e) => {