mirror of
https://github.com/open-webui/open-webui
synced 2025-05-17 20:05:08 +00:00
enh: drag and drop chat exports
This commit is contained in:
parent
3516eea189
commit
b38e2fab32
@ -2,20 +2,27 @@
|
|||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
|
|
||||||
export let title = '';
|
export let title = '';
|
||||||
|
export let content = '';
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class=" text-center text-6xl mb-3">📄</div>
|
<div class="px-3">
|
||||||
<div class="text-center dark:text-white text-2xl font-semibold z-50">
|
<div class="text-center text-6xl mb-3">📄</div>
|
||||||
|
<div class="text-center dark:text-white text-xl font-semibold z-50">
|
||||||
{#if title}
|
{#if title}
|
||||||
{title}
|
{title}
|
||||||
{:else}
|
{:else}
|
||||||
{$i18n.t('Add Files')}
|
{$i18n.t('Add Files')}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
|
||||||
|
|
||||||
<slot
|
|
||||||
><div class=" mt-2 text-center text-sm dark:text-gray-200 w-full">
|
|
||||||
{$i18n.t('Drop any files here to add to the conversation')}
|
|
||||||
</div>
|
</div>
|
||||||
</slot>
|
|
||||||
|
<slot
|
||||||
|
><div class="px-2 mt-2 text-center text-sm dark:text-gray-200 w-full">
|
||||||
|
{#if content}
|
||||||
|
{content}
|
||||||
|
{:else}
|
||||||
|
{$i18n.t('Drop any files here to add to the conversation')}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
showOverview,
|
showOverview,
|
||||||
showControls
|
showControls
|
||||||
} from '$lib/stores';
|
} from '$lib/stores';
|
||||||
import { onMount, getContext, tick } from 'svelte';
|
import { onMount, getContext, tick, onDestroy } from 'svelte';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -33,7 +33,8 @@
|
|||||||
getAllChatTags,
|
getAllChatTags,
|
||||||
archiveChatById,
|
archiveChatById,
|
||||||
cloneChatById,
|
cloneChatById,
|
||||||
getChatListBySearchText
|
getChatListBySearchText,
|
||||||
|
createNewChat
|
||||||
} from '$lib/apis/chats';
|
} from '$lib/apis/chats';
|
||||||
import { WEBUI_BASE_URL } from '$lib/constants';
|
import { WEBUI_BASE_URL } from '$lib/constants';
|
||||||
|
|
||||||
@ -43,6 +44,8 @@
|
|||||||
import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||||
import Spinner from '../common/Spinner.svelte';
|
import Spinner from '../common/Spinner.svelte';
|
||||||
import Loader from '../common/Loader.svelte';
|
import Loader from '../common/Loader.svelte';
|
||||||
|
import FilesOverlay from '../chat/MessageInput/FilesOverlay.svelte';
|
||||||
|
import AddFilesPlaceholder from '../AddFilesPlaceholder.svelte';
|
||||||
|
|
||||||
const BREAKPOINT = 768;
|
const BREAKPOINT = 768;
|
||||||
|
|
||||||
@ -115,24 +118,81 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMount(async () => {
|
const deleteChatHandler = async (id) => {
|
||||||
mobile.subscribe((e) => {
|
const res = await deleteChatById(localStorage.token, id).catch((error) => {
|
||||||
if ($showSidebar && e) {
|
toast.error(error);
|
||||||
showSidebar.set(false);
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
if (!$showSidebar && !e) {
|
|
||||||
showSidebar.set(true);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
showSidebar.set(!$mobile ? localStorage.sidebar === 'true' : false);
|
if (res) {
|
||||||
showSidebar.subscribe((value) => {
|
if ($chatId === id) {
|
||||||
localStorage.sidebar = value;
|
await chatId.set('');
|
||||||
});
|
await tick();
|
||||||
|
goto('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
allChatsLoaded = false;
|
||||||
|
currentChatPage.set(1);
|
||||||
|
await chats.set(await getChatList(localStorage.token, $currentChatPage));
|
||||||
|
|
||||||
await pinnedChats.set(await getChatListByTagName(localStorage.token, 'pinned'));
|
await pinnedChats.set(await getChatListByTagName(localStorage.token, 'pinned'));
|
||||||
await initChatList();
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const inputFilesHandler = async (files) => {
|
||||||
|
console.log(files);
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = async (e) => {
|
||||||
|
const content = e.target.result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const items = JSON.parse(content);
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.chat) {
|
||||||
|
await createNewChat(localStorage.token, item.chat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
toast.error($i18n.t(`Invalid file format.`));
|
||||||
|
}
|
||||||
|
|
||||||
|
initChatList();
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsText(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let dragged = false;
|
||||||
|
|
||||||
|
const onDragOver = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
dragged = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDragLeave = () => {
|
||||||
|
dragged = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDrop = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
console.log(e);
|
||||||
|
|
||||||
|
if (e.dataTransfer?.files) {
|
||||||
|
const inputFiles = Array.from(e.dataTransfer?.files);
|
||||||
|
if (inputFiles && inputFiles.length > 0) {
|
||||||
|
console.log(inputFiles);
|
||||||
|
inputFilesHandler(inputFiles);
|
||||||
|
} else {
|
||||||
|
toast.error($i18n.t(`File not found.`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dragged = false;
|
||||||
|
};
|
||||||
|
|
||||||
let touchstart;
|
let touchstart;
|
||||||
let touchend;
|
let touchend;
|
||||||
@ -179,6 +239,25 @@
|
|||||||
selectedChatId = null;
|
selectedChatId = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
mobile.subscribe((e) => {
|
||||||
|
if ($showSidebar && e) {
|
||||||
|
showSidebar.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$showSidebar && !e) {
|
||||||
|
showSidebar.set(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
showSidebar.set(!$mobile ? localStorage.sidebar === 'true' : false);
|
||||||
|
showSidebar.subscribe((value) => {
|
||||||
|
localStorage.sidebar = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
await pinnedChats.set(await getChatListByTagName(localStorage.token, 'pinned'));
|
||||||
|
await initChatList();
|
||||||
|
|
||||||
window.addEventListener('keydown', onKeyDown);
|
window.addEventListener('keydown', onKeyDown);
|
||||||
window.addEventListener('keyup', onKeyUp);
|
window.addEventListener('keyup', onKeyUp);
|
||||||
|
|
||||||
@ -188,7 +267,14 @@
|
|||||||
window.addEventListener('focus', onFocus);
|
window.addEventListener('focus', onFocus);
|
||||||
window.addEventListener('blur', onBlur);
|
window.addEventListener('blur', onBlur);
|
||||||
|
|
||||||
return () => {
|
const dropZone = document.getElementById('sidebar');
|
||||||
|
|
||||||
|
dropZone?.addEventListener('dragover', onDragOver);
|
||||||
|
dropZone?.addEventListener('drop', onDrop);
|
||||||
|
dropZone?.addEventListener('dragleave', onDragLeave);
|
||||||
|
});
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
window.removeEventListener('keydown', onKeyDown);
|
window.removeEventListener('keydown', onKeyDown);
|
||||||
window.removeEventListener('keyup', onKeyUp);
|
window.removeEventListener('keyup', onKeyUp);
|
||||||
|
|
||||||
@ -197,29 +283,13 @@
|
|||||||
|
|
||||||
window.removeEventListener('focus', onFocus);
|
window.removeEventListener('focus', onFocus);
|
||||||
window.removeEventListener('blur', onBlur);
|
window.removeEventListener('blur', onBlur);
|
||||||
};
|
|
||||||
|
const dropZone = document.getElementById('sidebar');
|
||||||
|
|
||||||
|
dropZone?.removeEventListener('dragover', onDragOver);
|
||||||
|
dropZone?.removeEventListener('drop', onDrop);
|
||||||
|
dropZone?.removeEventListener('dragleave', onDragLeave);
|
||||||
});
|
});
|
||||||
|
|
||||||
const deleteChatHandler = async (id) => {
|
|
||||||
const res = await deleteChatById(localStorage.token, id).catch((error) => {
|
|
||||||
toast.error(error);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
if ($chatId === id) {
|
|
||||||
await chatId.set('');
|
|
||||||
await tick();
|
|
||||||
goto('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
allChatsLoaded = false;
|
|
||||||
currentChatPage.set(1);
|
|
||||||
await chats.set(await getChatList(localStorage.token, $currentChatPage));
|
|
||||||
|
|
||||||
await pinnedChats.set(await getChatListByTagName(localStorage.token, 'pinned'));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ArchivedChatsModal
|
<ArchivedChatsModal
|
||||||
@ -261,6 +331,18 @@
|
|||||||
"
|
"
|
||||||
data-state={$showSidebar}
|
data-state={$showSidebar}
|
||||||
>
|
>
|
||||||
|
{#if dragged}
|
||||||
|
<div
|
||||||
|
class="absolute w-full h-full max-h-full backdrop-blur bg-gray-800/40 flex justify-center z-[999] touch-none pointer-events-none"
|
||||||
|
>
|
||||||
|
<div class="m-auto pt-64 flex flex-col justify-center">
|
||||||
|
<AddFilesPlaceholder
|
||||||
|
title={$i18n.t('Drop Chat Export')}
|
||||||
|
content={$i18n.t('Drop a chat export file here to import it.')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<div
|
<div
|
||||||
class="py-2.5 my-auto flex flex-col justify-between h-screen max-h-[100dvh] w-[260px] z-50 {$showSidebar
|
class="py-2.5 my-auto flex flex-col justify-between h-screen max-h-[100dvh] w-[260px] z-50 {$showSidebar
|
||||||
? ''
|
? ''
|
||||||
|
Loading…
Reference in New Issue
Block a user