mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-12 12:25:20 +00:00
enh: folders
This commit is contained in:
parent
3251f8b14d
commit
37c2fb0aa8
11 changed files with 361 additions and 50 deletions
|
|
@ -49,7 +49,7 @@ async def get_folders(user=Depends(get_verified_user)):
|
||||||
**folder.model_dump(),
|
**folder.model_dump(),
|
||||||
"items": {
|
"items": {
|
||||||
"chats": [
|
"chats": [
|
||||||
{"title": chat.title, "id": chat.id}
|
{"title": chat.title, "id": chat.id, "updated_at": chat.updated_at}
|
||||||
for chat in Chats.get_chats_by_folder_id_and_user_id(
|
for chat in Chats.get_chats_by_folder_id_and_user_id(
|
||||||
folder.id, user.id
|
folder.id, user.id
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2113,8 +2113,8 @@
|
||||||
showBanners={!showCommands}
|
showBanners={!showCommands}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="flex flex-col flex-auto z-10 w-full @container">
|
<div class="flex flex-col flex-auto z-10 w-full @container overflow-auto">
|
||||||
{#if $settings?.landingPageMode === 'chat' || createMessagesList(history, history.currentId).length > 0}
|
{#if ($settings?.landingPageMode === 'chat' && !$selectedFolder) || createMessagesList(history, history.currentId).length > 0}
|
||||||
<div
|
<div
|
||||||
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0 max-w-full z-10 scrollbar-hidden"
|
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0 max-w-full z-10 scrollbar-hidden"
|
||||||
id="messages-container"
|
id="messages-container"
|
||||||
|
|
@ -2212,7 +2212,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="overflow-auto w-full h-full flex items-center">
|
<div class="flex items-center h-full">
|
||||||
<Placeholder
|
<Placeholder
|
||||||
{history}
|
{history}
|
||||||
{selectedModels}
|
{selectedModels}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@
|
||||||
user,
|
user,
|
||||||
models as _models,
|
models as _models,
|
||||||
temporaryChatEnabled,
|
temporaryChatEnabled,
|
||||||
selectedFolder
|
selectedFolder,
|
||||||
|
chats,
|
||||||
|
currentChatPage
|
||||||
} from '$lib/stores';
|
} from '$lib/stores';
|
||||||
import { sanitizeResponseContent, extractCurlyBraceWords } from '$lib/utils';
|
import { sanitizeResponseContent, extractCurlyBraceWords } from '$lib/utils';
|
||||||
import { WEBUI_BASE_URL } from '$lib/constants';
|
import { WEBUI_BASE_URL } from '$lib/constants';
|
||||||
|
|
@ -21,9 +23,9 @@
|
||||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||||
import EyeSlash from '$lib/components/icons/EyeSlash.svelte';
|
import EyeSlash from '$lib/components/icons/EyeSlash.svelte';
|
||||||
import MessageInput from './MessageInput.svelte';
|
import MessageInput from './MessageInput.svelte';
|
||||||
import FolderOpen from '../icons/FolderOpen.svelte';
|
import FolderPlaceholder from './Placeholder/FolderPlaceholder.svelte';
|
||||||
import XMark from '../icons/XMark.svelte';
|
import FolderTitle from './Placeholder/FolderTitle.svelte';
|
||||||
import Folder from '../icons/Folder.svelte';
|
import { getChatList } from '$lib/apis/chats';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
|
@ -87,29 +89,21 @@
|
||||||
>
|
>
|
||||||
<div class="w-full flex flex-col justify-center items-center">
|
<div class="w-full flex flex-col justify-center items-center">
|
||||||
{#if $selectedFolder}
|
{#if $selectedFolder}
|
||||||
<div class="mb-3 px-4 justify-center w-fit flex relative group">
|
<FolderTitle
|
||||||
<div class="text-center flex gap-3.5 items-center">
|
folder={$selectedFolder}
|
||||||
<div class=" rounded-full bg-gray-50 dark:bg-gray-800 p-3 w-fit">
|
onUpdate={async (folder) => {
|
||||||
<Folder className="size-4.5" strokeWidth="2" />
|
selectedFolder.set(folder);
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-3xl">
|
await chats.set(await getChatList(localStorage.token, $currentChatPage));
|
||||||
{$selectedFolder?.name}
|
currentChatPage.set(1);
|
||||||
</div>
|
}}
|
||||||
</div>
|
onDelete={async () => {
|
||||||
|
await chats.set(await getChatList(localStorage.token, $currentChatPage));
|
||||||
|
currentChatPage.set(1);
|
||||||
|
|
||||||
<div class="absolute -right-3">
|
selectedFolder.set(null);
|
||||||
<button
|
}}
|
||||||
class="group-hover:visible invisible rounded-md"
|
/>
|
||||||
type="button"
|
|
||||||
on:click={() => {
|
|
||||||
selectedFolder.set(null);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<XMark className="size-4" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{:else}
|
{:else}
|
||||||
<div class="flex flex-row justify-center gap-3 @sm:gap-3.5 w-fit px-5 max-w-xl">
|
<div class="flex flex-row justify-center gap-3 @sm:gap-3.5 w-fit px-5 max-w-xl">
|
||||||
<div class="flex shrink-0 justify-center">
|
<div class="flex shrink-0 justify-center">
|
||||||
|
|
@ -249,16 +243,26 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mx-auto max-w-2xl font-primary mt-2" in:fade={{ duration: 200, delay: 200 }}>
|
|
||||||
<div class="mx-5">
|
{#if $selectedFolder}
|
||||||
<Suggestions
|
<div
|
||||||
suggestionPrompts={atSelectedModel?.info?.meta?.suggestion_prompts ??
|
class="mx-auto px-4 md:max-w-3xl md:px-6 font-primary min-h-62"
|
||||||
models[selectedModelIdx]?.info?.meta?.suggestion_prompts ??
|
in:fade={{ duration: 200, delay: 200 }}
|
||||||
$config?.default_prompt_suggestions ??
|
>
|
||||||
[]}
|
<FolderPlaceholder folder={$selectedFolder} />
|
||||||
inputValue={prompt}
|
|
||||||
{onSelect}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{:else}
|
||||||
|
<div class="mx-auto max-w-2xl font-primary mt-2" in:fade={{ duration: 200, delay: 200 }}>
|
||||||
|
<div class="mx-5">
|
||||||
|
<Suggestions
|
||||||
|
suggestionPrompts={atSelectedModel?.info?.meta?.suggestion_prompts ??
|
||||||
|
models[selectedModelIdx]?.info?.meta?.suggestion_prompts ??
|
||||||
|
$config?.default_prompt_suggestions ??
|
||||||
|
[]}
|
||||||
|
inputValue={prompt}
|
||||||
|
{onSelect}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
103
src/lib/components/chat/Placeholder/ChatList.svelte
Normal file
103
src/lib/components/chat/Placeholder/ChatList.svelte
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { getContext, onMount } from 'svelte';
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
||||||
|
import { getTimeRange } from '$lib/utils';
|
||||||
|
|
||||||
|
dayjs.extend(localizedFormat);
|
||||||
|
|
||||||
|
export let chats = [];
|
||||||
|
|
||||||
|
let chatList = null;
|
||||||
|
|
||||||
|
const init = async () => {
|
||||||
|
if (chats.length === 0) {
|
||||||
|
chatList = [];
|
||||||
|
} else {
|
||||||
|
chatList = chats.map((chat) => ({
|
||||||
|
...chat,
|
||||||
|
time_range: getTimeRange(chat.updated_at)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$: if (chats) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if chatList}
|
||||||
|
<div class="text-left text-sm w-full mb-3">
|
||||||
|
{#if chatList.length === 0}
|
||||||
|
<div
|
||||||
|
class="text-xs text-gray-500 dark:text-gray-400 text-center px-5 min-h-20 w-full h-full flex justify-center items-center"
|
||||||
|
>
|
||||||
|
{$i18n.t('No chats found')}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#each chatList as chat, idx (chat.id)}
|
||||||
|
{#if (idx === 0 || (idx > 0 && chat.time_range !== chatList[idx - 1].time_range)) && chat?.time_range}
|
||||||
|
<div
|
||||||
|
class="w-full text-xs text-gray-500 dark:text-gray-500 font-medium {idx === 0
|
||||||
|
? ''
|
||||||
|
: 'pt-5'} pb-2 px-2"
|
||||||
|
>
|
||||||
|
{$i18n.t(chat.time_range)}
|
||||||
|
<!-- localisation keys for time_range to be recognized from the i18next parser (so they don't get automatically removed):
|
||||||
|
{$i18n.t('Today')}
|
||||||
|
{$i18n.t('Yesterday')}
|
||||||
|
{$i18n.t('Previous 7 days')}
|
||||||
|
{$i18n.t('Previous 30 days')}
|
||||||
|
{$i18n.t('January')}
|
||||||
|
{$i18n.t('February')}
|
||||||
|
{$i18n.t('March')}
|
||||||
|
{$i18n.t('April')}
|
||||||
|
{$i18n.t('May')}
|
||||||
|
{$i18n.t('June')}
|
||||||
|
{$i18n.t('July')}
|
||||||
|
{$i18n.t('August')}
|
||||||
|
{$i18n.t('September')}
|
||||||
|
{$i18n.t('October')}
|
||||||
|
{$i18n.t('November')}
|
||||||
|
{$i18n.t('December')}
|
||||||
|
-->
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<a
|
||||||
|
class=" w-full flex justify-between items-center rounded-lg text-sm py-2 px-3 hover:bg-gray-50 dark:hover:bg-gray-850"
|
||||||
|
draggable="false"
|
||||||
|
href={`/c/${chat.id}`}
|
||||||
|
on:click={() => (show = false)}
|
||||||
|
>
|
||||||
|
<div class="text-ellipsis line-clamp-1 w-full sm:basis-3/5">
|
||||||
|
{chat?.title}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden sm:flex sm:basis-2/5 items-center justify-end">
|
||||||
|
<div class=" text-gray-500 dark:text-gray-400 text-xs">
|
||||||
|
{dayjs(chat?.updated_at * 1000).calendar()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
<!-- {#if !allChatsLoaded && loadHandler}
|
||||||
|
<Loader
|
||||||
|
on:visible={(e) => {
|
||||||
|
if (!chatListLoading) {
|
||||||
|
loadHandler();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="w-full flex justify-center py-1 text-xs animate-pulse items-center gap-2">
|
||||||
|
<Spinner className=" size-4" />
|
||||||
|
<div class=" ">Loading...</div>
|
||||||
|
</div>
|
||||||
|
</Loader>
|
||||||
|
{/if} -->
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
51
src/lib/components/chat/Placeholder/FolderPlaceholder.svelte
Normal file
51
src/lib/components/chat/Placeholder/FolderPlaceholder.svelte
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
<script>
|
||||||
|
import { getContext } from 'svelte';
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
|
|
||||||
|
import ChatList from './ChatList.svelte';
|
||||||
|
import FolderKnowledge from './FolderKnowledge.svelte';
|
||||||
|
|
||||||
|
export let folder = null;
|
||||||
|
|
||||||
|
let selectedTab = 'chats';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<!-- <div class="mb-1">
|
||||||
|
<div
|
||||||
|
class="flex gap-1 scrollbar-none overflow-x-auto w-fit text-center text-sm font-medium rounded-full bg-transparent py-1 touch-auto pointer-events-auto"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="min-w-fit p-1.5 {selectedTab === 'knowledge'
|
||||||
|
? ''
|
||||||
|
: 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition"
|
||||||
|
type="button"
|
||||||
|
on:click={() => {
|
||||||
|
selectedTab = 'knowledge';
|
||||||
|
}}>{$i18n.t('Knowledge')}</button
|
||||||
|
>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="min-w-fit p-1.5 {selectedTab === 'chats'
|
||||||
|
? ''
|
||||||
|
: 'text-gray-300 dark:text-gray-600 hover:text-gray-700 dark:hover:text-white'} transition"
|
||||||
|
type="button"
|
||||||
|
on:click={() => {
|
||||||
|
selectedTab = 'chats';
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{$i18n.t('Chats')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<div class="">
|
||||||
|
{#if selectedTab === 'knowledge'}
|
||||||
|
<FolderKnowledge />
|
||||||
|
{:else if selectedTab === 'chats'}
|
||||||
|
<ChatList chats={folder?.items?.chats ?? []} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
147
src/lib/components/chat/Placeholder/FolderTitle.svelte
Normal file
147
src/lib/components/chat/Placeholder/FolderTitle.svelte
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { getContext } from 'svelte';
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
import DOMPurify from 'dompurify';
|
||||||
|
|
||||||
|
import fileSaver from 'file-saver';
|
||||||
|
const { saveAs } = fileSaver;
|
||||||
|
|
||||||
|
import { toast } from 'svelte-sonner';
|
||||||
|
|
||||||
|
import { selectedFolder } from '$lib/stores';
|
||||||
|
|
||||||
|
import { deleteFolderById, updateFolderById } from '$lib/apis/folders';
|
||||||
|
import { getChatsByFolderId } from '$lib/apis/chats';
|
||||||
|
|
||||||
|
import FolderModal from '$lib/components/layout/Sidebar/Folders/FolderModal.svelte';
|
||||||
|
|
||||||
|
import Folder from '$lib/components/icons/Folder.svelte';
|
||||||
|
import XMark from '$lib/components/icons/XMark.svelte';
|
||||||
|
import FolderMenu from '$lib/components/layout/Sidebar/Folders/FolderMenu.svelte';
|
||||||
|
import EllipsisHorizontal from '$lib/components/icons/EllipsisHorizontal.svelte';
|
||||||
|
import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||||
|
|
||||||
|
export let folder = null;
|
||||||
|
|
||||||
|
export let onUpdate: Function = (folderId) => {};
|
||||||
|
export let onDelete: Function = (folderId) => {};
|
||||||
|
|
||||||
|
let showFolderModal = false;
|
||||||
|
let showDeleteConfirm = false;
|
||||||
|
|
||||||
|
const updateHandler = async ({ name, data }) => {
|
||||||
|
if (name === '') {
|
||||||
|
toast.error($i18n.t('Folder name cannot be empty.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentName = folder.name;
|
||||||
|
|
||||||
|
name = name.trim();
|
||||||
|
folder.name = name;
|
||||||
|
|
||||||
|
const res = await updateFolderById(localStorage.token, folder.id, {
|
||||||
|
name,
|
||||||
|
...(data ? { data } : {})
|
||||||
|
}).catch((error) => {
|
||||||
|
toast.error(`${error}`);
|
||||||
|
|
||||||
|
folder.name = currentName;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
folder.name = name;
|
||||||
|
if (data) {
|
||||||
|
folder.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.success($i18n.t('Folder updated successfully'));
|
||||||
|
selectedFolder.set(folder);
|
||||||
|
onUpdate(folder);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteHandler = async () => {
|
||||||
|
const res = await deleteFolderById(localStorage.token, folder.id).catch((error) => {
|
||||||
|
toast.error(`${error}`);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
toast.success($i18n.t('Folder deleted successfully'));
|
||||||
|
onDelete(folder);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportHandler = async () => {
|
||||||
|
const chats = await getChatsByFolderId(localStorage.token, folder.id).catch((error) => {
|
||||||
|
toast.error(`${error}`);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
if (!chats) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob([JSON.stringify(chats)], {
|
||||||
|
type: 'application/json'
|
||||||
|
});
|
||||||
|
|
||||||
|
saveAs(blob, `folder-${folder.name}-export-${Date.now()}.json`);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if folder}
|
||||||
|
<FolderModal bind:show={showFolderModal} edit={true} {folder} onSubmit={updateHandler} />
|
||||||
|
|
||||||
|
<DeleteConfirmDialog
|
||||||
|
bind:show={showDeleteConfirm}
|
||||||
|
title={$i18n.t('Delete folder?')}
|
||||||
|
on:confirm={() => {
|
||||||
|
deleteHandler();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class=" text-sm text-gray-700 dark:text-gray-300 flex-1 line-clamp-3">
|
||||||
|
{@html DOMPurify.sanitize(
|
||||||
|
$i18n.t(
|
||||||
|
'This will delete <strong>{{NAME}}</strong> and <strong>all its contents</strong>.',
|
||||||
|
{
|
||||||
|
NAME: folder.name
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</DeleteConfirmDialog>
|
||||||
|
|
||||||
|
<div class="mb-3 px-6 @md:max-w-3xl justify-between w-full flex relative group items-center">
|
||||||
|
<div class="text-center flex gap-3.5 items-center">
|
||||||
|
<div class=" rounded-full bg-gray-50 dark:bg-gray-800 p-3 w-fit">
|
||||||
|
<Folder className="size-4.5" strokeWidth="2" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-3xl">
|
||||||
|
{folder.name}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center">
|
||||||
|
<FolderMenu
|
||||||
|
align="end"
|
||||||
|
onEdit={() => {
|
||||||
|
showFolderModal = true;
|
||||||
|
}}
|
||||||
|
onDelete={() => {
|
||||||
|
showDeleteConfirm = true;
|
||||||
|
}}
|
||||||
|
onExport={() => {
|
||||||
|
exportHandler();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button class="p-1.5 dark:hover:bg-gray-850 rounded-full touch-auto" on:click={(e) => {}}>
|
||||||
|
<EllipsisHorizontal className="size-4" strokeWidth="2.5" />
|
||||||
|
</button>
|
||||||
|
</FolderMenu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
@ -363,9 +363,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
chats.subscribe((value) => {
|
chats.subscribe((value) => {
|
||||||
if ($selectedFolder) {
|
initFolders();
|
||||||
initFolders();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await initChannels();
|
await initChannels();
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||||
import Download from '$lib/components/icons/Download.svelte';
|
import Download from '$lib/components/icons/Download.svelte';
|
||||||
|
|
||||||
|
export let align: 'start' | 'end' = 'start';
|
||||||
export let onEdit = () => {};
|
export let onEdit = () => {};
|
||||||
export let onExport = () => {};
|
export let onExport = () => {};
|
||||||
export let onDelete = () => {};
|
export let onDelete = () => {};
|
||||||
|
|
@ -36,7 +37,7 @@
|
||||||
class="w-full max-w-[170px] rounded-lg px-1 py-1.5 z-50 bg-white dark:bg-gray-850 dark:text-white shadow-lg"
|
class="w-full max-w-[170px] rounded-lg px-1 py-1.5 z-50 bg-white dark:bg-gray-850 dark:text-white shadow-lg"
|
||||||
sideOffset={-2}
|
sideOffset={-2}
|
||||||
side="bottom"
|
side="bottom"
|
||||||
align="start"
|
{align}
|
||||||
transition={flyAndScale}
|
transition={flyAndScale}
|
||||||
>
|
>
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
export let show = false;
|
export let show = false;
|
||||||
export let onSubmit: Function = (e) => {};
|
export let onSubmit: Function = (e) => {};
|
||||||
|
|
||||||
|
export let edit = false;
|
||||||
|
|
||||||
export let folder = null;
|
export let folder = null;
|
||||||
|
|
||||||
let name = '';
|
let name = '';
|
||||||
|
|
@ -53,7 +55,11 @@
|
||||||
<div>
|
<div>
|
||||||
<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-1">
|
<div class=" flex justify-between dark:text-gray-300 px-5 pt-4 pb-1">
|
||||||
<div class=" text-lg font-medium self-center">
|
<div class=" text-lg font-medium self-center">
|
||||||
{$i18n.t('Edit Folder')}
|
{#if edit}
|
||||||
|
{$i18n.t('Edit Folder')}
|
||||||
|
{:else}
|
||||||
|
{$i18n.t('Create Folder')}
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="self-center"
|
class="self-center"
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
import ChatItem from './ChatItem.svelte';
|
import ChatItem from './ChatItem.svelte';
|
||||||
import FolderMenu from './Folders/FolderMenu.svelte';
|
import FolderMenu from './Folders/FolderMenu.svelte';
|
||||||
import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||||
import EditFolderModal from './Folders/EditFolderModal.svelte';
|
import FolderModal from './Folders/FolderModal.svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
|
||||||
export let open = false;
|
export let open = false;
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
|
|
||||||
let folderElement;
|
let folderElement;
|
||||||
|
|
||||||
let showEditFolderModal = false;
|
let showFolderModal = false;
|
||||||
let edit = false;
|
let edit = false;
|
||||||
|
|
||||||
let draggedOver = false;
|
let draggedOver = false;
|
||||||
|
|
@ -378,8 +378,9 @@
|
||||||
</div>
|
</div>
|
||||||
</DeleteConfirmDialog>
|
</DeleteConfirmDialog>
|
||||||
|
|
||||||
<EditFolderModal
|
<FolderModal
|
||||||
bind:show={showEditFolderModal}
|
bind:show={showFolderModal}
|
||||||
|
edit={true}
|
||||||
folder={folders[folderId]}
|
folder={folders[folderId]}
|
||||||
onSubmit={updateHandler}
|
onSubmit={updateHandler}
|
||||||
/>
|
/>
|
||||||
|
|
@ -482,7 +483,7 @@
|
||||||
>
|
>
|
||||||
<FolderMenu
|
<FolderMenu
|
||||||
onEdit={() => {
|
onEdit={() => {
|
||||||
showEditFolderModal = true;
|
showFolderModal = true;
|
||||||
}}
|
}}
|
||||||
onDelete={() => {
|
onDelete={() => {
|
||||||
showDeleteConfirm = true;
|
showDeleteConfirm = true;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue