feat: document select

This commit is contained in:
Timothy J. Baek 2024-02-25 21:16:11 -08:00
parent f8cf43c0f7
commit 63628a70a6
2 changed files with 176 additions and 24 deletions

View file

@ -0,0 +1,70 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
export let state = 'unchecked';
export let indeterminate = false;
let _state = 'unchecked';
$: _state = state;
</script>
<button
class=" outline -outline-offset-1 outline-[1.5px] outline-gray-200 dark:outline-gray-600 {state !==
'unchecked'
? 'bg-black outline-black '
: 'hover:outline-gray-500 hover:bg-gray-50 dark:hover:bg-gray-800'} text-white transition-all rounded inline-block w-3.5 h-3.5 relative"
on:click={() => {
if (_state === 'unchecked') {
_state = 'checked';
dispatch('change', _state);
} else if (_state === 'checked') {
_state = 'unchecked';
if (!indeterminate) {
dispatch('change', _state);
}
} else if (indeterminate) {
_state = 'checked';
dispatch('change', _state);
}
}}
>
<div class="top-0 left-0 absolute w-full flex justify-center">
{#if _state === 'checked'}
<svg
class="w-3.5 h-3.5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="3"
d="m5 12 4.7 4.5 9.3-9"
/>
</svg>
{:else if indeterminate}
<svg
class="w-3 h-3.5 text-gray-800 dark:text-white"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="3"
d="M5 12h14"
/>
</svg>
{/if}
</div>
<!-- {checked} -->
</button>

View file

@ -11,6 +11,8 @@
import { uploadDocToVectorDB } from '$lib/apis/rag'; import { uploadDocToVectorDB } from '$lib/apis/rag';
import { transformFileName } from '$lib/utils'; import { transformFileName } from '$lib/utils';
import Checkbox from '$lib/components/common/Checkbox.svelte';
import EditDocModal from '$lib/components/documents/EditDocModal.svelte'; import EditDocModal from '$lib/components/documents/EditDocModal.svelte';
import AddFilesPlaceholder from '$lib/components/AddFilesPlaceholder.svelte'; import AddFilesPlaceholder from '$lib/components/AddFilesPlaceholder.svelte';
import SettingsModal from '$lib/components/documents/SettingsModal.svelte'; import SettingsModal from '$lib/components/documents/SettingsModal.svelte';
@ -33,6 +35,16 @@
await documents.set(await getDocs(localStorage.token)); await documents.set(await getDocs(localStorage.token));
}; };
const deleteDocs = async (docs) => {
const res = await Promise.all(
docs.map(async (doc) => {
return await deleteDocByName(localStorage.token, doc.name);
})
);
await documents.set(await getDocs(localStorage.token));
};
const uploadDoc = async (file) => { const uploadDoc = async (file) => {
const res = await uploadDocToVectorDB(localStorage.token, '', file).catch((error) => { const res = await uploadDocToVectorDB(localStorage.token, '', file).catch((error) => {
toast.error(error); toast.error(error);
@ -123,6 +135,15 @@
dropZone?.removeEventListener('dragleave', onDragLeave); dropZone?.removeEventListener('dragleave', onDragLeave);
}; };
}); });
let filteredDocs;
$: filteredDocs = $documents.filter(
(doc) =>
(selectedTag === '' ||
(doc?.content?.tags ?? []).map((tag) => tag.name).includes(selectedTag)) &&
(query === '' || doc.name.includes(query))
);
</script> </script>
{#if dragged} {#if dragged}
@ -287,6 +308,26 @@
{#if tags.length > 0} {#if tags.length > 0}
<div class="px-2.5 pt-1 flex gap-1 flex-wrap"> <div class="px-2.5 pt-1 flex gap-1 flex-wrap">
<div class="ml-0.5 pr-3 my-auto flex items-center">
<Checkbox
state={filteredDocs.filter((doc) => doc?.selected === 'checked').length ===
filteredDocs.length
? 'checked'
: 'unchecked'}
indeterminate={filteredDocs.filter((doc) => doc?.selected === 'checked').length > 0 &&
filteredDocs.filter((doc) => doc?.selected === 'checked').length !==
filteredDocs.length}
on:change={(e) => {
if (e.detail === 'checked') {
filteredDocs = filteredDocs.map((doc) => ({ ...doc, selected: 'checked' }));
} else if (e.detail === 'unchecked') {
filteredDocs = filteredDocs.map((doc) => ({ ...doc, selected: 'unchecked' }));
}
}}
/>
</div>
{#if filteredDocs.filter((doc) => doc?.selected === 'checked').length === 0}
<button <button
class="px-2 py-0.5 space-x-1 flex h-fit items-center rounded-full transition bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:text-white" class="px-2 py-0.5 space-x-1 flex h-fit items-center rounded-full transition bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:text-white"
on:click={async () => { on:click={async () => {
@ -296,6 +337,7 @@
> >
<div class=" text-xs font-medium self-center line-clamp-1">all</div> <div class=" text-xs font-medium self-center line-clamp-1">all</div>
</button> </button>
{#each tags as tag} {#each tags as tag}
<button <button
class="px-2 py-0.5 space-x-1 flex h-fit items-center rounded-full transition bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:text-white" class="px-2 py-0.5 space-x-1 flex h-fit items-center rounded-full transition bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:text-white"
@ -309,16 +351,53 @@
</div> </div>
</button> </button>
{/each} {/each}
{:else}
<div class="flex-1 flex w-full justify-between items-center">
<div class="text-xs font-medium py-0.5 self-center mr-1">
{filteredDocs.filter((doc) => doc?.selected === 'checked').length} Selected
</div>
<div class="flex gap-1">
<button
class="px-2 py-0.5 space-x-1 flex h-fit items-center rounded-full transition bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:text-white"
on:click={async () => {
selectedTag = '';
// await chats.set(await getChatListByTagName(localStorage.token, tag.name));
}}
>
<div class=" text-xs font-medium self-center line-clamp-1">tag</div>
</button>
<button
class="px-2 py-0.5 space-x-1 flex h-fit items-center rounded-full transition bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:text-white"
on:click={async () => {
deleteDocs(filteredDocs.filter((doc) => doc.selected === 'checked'));
// await chats.set(await getChatListByTagName(localStorage.token, tag.name));
}}
>
<div class=" text-xs font-medium self-center line-clamp-1">delete</div>
</button>
</div>
</div>
{/if}
</div> </div>
{/if} {/if}
<div class="my-3 mb-5"> <div class="my-3 mb-5">
{#each $documents.filter((doc) => (selectedTag === '' || (doc?.content?.tags ?? []) {#each filteredDocs as doc}
.map((tag) => tag.name) <button
.includes(selectedTag)) && (query === '' || doc.name.includes(query))) as doc} class=" flex space-x-4 cursor-pointer text-left w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
<div on:click={() => {
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl" if (doc?.selected === 'checked') {
doc.selected = 'unchecked';
} else {
doc.selected = 'checked';
}
}}
> >
<div class="my-auto flex items-center">
<Checkbox state={doc?.selected ?? 'unchecked'} />
</div>
<div class=" flex flex-1 space-x-4 cursor-pointer w-full"> <div class=" flex flex-1 space-x-4 cursor-pointer w-full">
<div class=" flex items-center space-x-3"> <div class=" flex items-center space-x-3">
<div class="p-2.5 bg-red-400 text-white rounded-lg"> <div class="p-2.5 bg-red-400 text-white rounded-lg">
@ -387,9 +466,10 @@
</div> </div>
<div class="flex flex-row space-x-1 self-center"> <div class="flex flex-row space-x-1 self-center">
<button <button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl" class="self-center w-fit text-sm z-20 px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button" type="button"
on:click={async () => { on:click={async (e) => {
e.stopPropagation();
showEditDocModal = !showEditDocModal; showEditDocModal = !showEditDocModal;
selectedDoc = doc; selectedDoc = doc;
}} }}
@ -435,7 +515,9 @@
<button <button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl" class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button" type="button"
on:click={() => { on:click={(e) => {
e.stopPropagation();
deleteDoc(doc.name); deleteDoc(doc.name);
}} }}
> >
@ -455,7 +537,7 @@
</svg> </svg>
</button> </button>
</div> </div>
</div> </button>
{/each} {/each}
</div> </div>