mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-13 04:45:19 +00:00
enh: note search
This commit is contained in:
parent
f5613fb3c2
commit
de343021c1
1 changed files with 71 additions and 3 deletions
|
|
@ -1,6 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { toast } from 'svelte-sonner';
|
||||
import fileSaver from 'file-saver';
|
||||
import Fuse from 'fuse.js';
|
||||
|
||||
const { saveAs } = fileSaver;
|
||||
|
||||
import jsPDF from 'jspdf';
|
||||
|
|
@ -32,7 +34,7 @@
|
|||
import { WEBUI_NAME, config, prompts as _prompts, user } from '$lib/stores';
|
||||
|
||||
import { createNewNote, deleteNoteById, getNotes } from '$lib/apis/notes';
|
||||
import { capitalizeFirstLetter, copyToClipboard } from '$lib/utils';
|
||||
import { capitalizeFirstLetter, copyToClipboard, getTimeRange } from '$lib/utils';
|
||||
|
||||
import EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte';
|
||||
import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||
|
|
@ -44,6 +46,7 @@
|
|||
import NoteMenu from './Notes/NoteMenu.svelte';
|
||||
import FilesOverlay from '../chat/MessageInput/FilesOverlay.svelte';
|
||||
import { marked } from 'marked';
|
||||
import XMark from '../icons/XMark.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
let loaded = false;
|
||||
|
|
@ -51,13 +54,50 @@
|
|||
let importFiles = '';
|
||||
let query = '';
|
||||
|
||||
let notes = [];
|
||||
let noteItems = [];
|
||||
let fuse = null;
|
||||
|
||||
let selectedNote = null;
|
||||
let notes = {};
|
||||
$: if (fuse) {
|
||||
notes = groupNotes(
|
||||
query
|
||||
? fuse.search(query).map((e) => {
|
||||
return e.item;
|
||||
})
|
||||
: noteItems
|
||||
);
|
||||
}
|
||||
|
||||
let showDeleteConfirm = false;
|
||||
|
||||
const groupNotes = (res) => {
|
||||
console.log(res);
|
||||
if (!Array.isArray(res)) {
|
||||
return {}; // or throw new Error("Notes response is not an array")
|
||||
}
|
||||
|
||||
// Build the grouped object
|
||||
const grouped: Record<string, any[]> = {};
|
||||
for (const note of res) {
|
||||
const timeRange = getTimeRange(note.updated_at / 1000000000);
|
||||
if (!grouped[timeRange]) {
|
||||
grouped[timeRange] = [];
|
||||
}
|
||||
grouped[timeRange].push({
|
||||
...note,
|
||||
timeRange
|
||||
});
|
||||
}
|
||||
return grouped;
|
||||
};
|
||||
|
||||
const init = async () => {
|
||||
notes = await getNotes(localStorage.token);
|
||||
noteItems = await getNotes(localStorage.token, true);
|
||||
|
||||
fuse = new Fuse(noteItems, {
|
||||
keys: ['title']
|
||||
});
|
||||
};
|
||||
|
||||
const createNoteHandler = async () => {
|
||||
|
|
@ -293,6 +333,34 @@
|
|||
</div>
|
||||
</DeleteConfirmDialog>
|
||||
|
||||
<div class="flex flex-col gap-1 px-3.5">
|
||||
<div class=" flex flex-1 items-center w-full space-x-2">
|
||||
<div class="flex flex-1 items-center">
|
||||
<div class=" self-center ml-1 mr-3">
|
||||
<Search className="size-3.5" />
|
||||
</div>
|
||||
<input
|
||||
class=" w-full text-sm py-1 rounded-r-xl outline-hidden bg-transparent"
|
||||
bind:value={query}
|
||||
placeholder={$i18n.t('Search Notes')}
|
||||
/>
|
||||
|
||||
{#if query}
|
||||
<div class="self-center pl-1.5 translate-y-[0.5px] rounded-l-xl bg-transparent">
|
||||
<button
|
||||
class="p-0.5 rounded-full hover:bg-gray-100 dark:hover:bg-gray-900 transition"
|
||||
on:click={() => {
|
||||
query = '';
|
||||
}}
|
||||
>
|
||||
<XMark className="size-3" strokeWidth="2" />
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-4.5 @container h-full pt-2">
|
||||
{#if Object.keys(notes).length > 0}
|
||||
<div class="pb-10">
|
||||
|
|
|
|||
Loading…
Reference in a new issue