|
@@ -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}
|