mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-16 11:57:51 +01:00
enh: note search
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
import fileSaver from 'file-saver';
|
import fileSaver from 'file-saver';
|
||||||
|
import Fuse from 'fuse.js';
|
||||||
|
|
||||||
const { saveAs } = fileSaver;
|
const { saveAs } = fileSaver;
|
||||||
|
|
||||||
import jsPDF from 'jspdf';
|
import jsPDF from 'jspdf';
|
||||||
@@ -32,7 +34,7 @@
|
|||||||
import { WEBUI_NAME, config, prompts as _prompts, user } from '$lib/stores';
|
import { WEBUI_NAME, config, prompts as _prompts, user } from '$lib/stores';
|
||||||
|
|
||||||
import { createNewNote, deleteNoteById, getNotes } from '$lib/apis/notes';
|
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 EllipsisHorizontal from '../icons/EllipsisHorizontal.svelte';
|
||||||
import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
|
||||||
@@ -44,6 +46,7 @@
|
|||||||
import NoteMenu from './Notes/NoteMenu.svelte';
|
import NoteMenu from './Notes/NoteMenu.svelte';
|
||||||
import FilesOverlay from '../chat/MessageInput/FilesOverlay.svelte';
|
import FilesOverlay from '../chat/MessageInput/FilesOverlay.svelte';
|
||||||
import { marked } from 'marked';
|
import { marked } from 'marked';
|
||||||
|
import XMark from '../icons/XMark.svelte';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
let loaded = false;
|
let loaded = false;
|
||||||
@@ -51,13 +54,50 @@
|
|||||||
let importFiles = '';
|
let importFiles = '';
|
||||||
let query = '';
|
let query = '';
|
||||||
|
|
||||||
let notes = [];
|
let noteItems = [];
|
||||||
|
let fuse = null;
|
||||||
|
|
||||||
let selectedNote = null;
|
let selectedNote = null;
|
||||||
|
let notes = {};
|
||||||
|
$: if (fuse) {
|
||||||
|
notes = groupNotes(
|
||||||
|
query
|
||||||
|
? fuse.search(query).map((e) => {
|
||||||
|
return e.item;
|
||||||
|
})
|
||||||
|
: noteItems
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let showDeleteConfirm = false;
|
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 () => {
|
const init = async () => {
|
||||||
notes = await getNotes(localStorage.token);
|
noteItems = await getNotes(localStorage.token, true);
|
||||||
|
|
||||||
|
fuse = new Fuse(noteItems, {
|
||||||
|
keys: ['title']
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const createNoteHandler = async () => {
|
const createNoteHandler = async () => {
|
||||||
@@ -293,6 +333,34 @@
|
|||||||
</div>
|
</div>
|
||||||
</DeleteConfirmDialog>
|
</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">
|
<div class="px-4.5 @container h-full pt-2">
|
||||||
{#if Object.keys(notes).length > 0}
|
{#if Object.keys(notes).length > 0}
|
||||||
<div class="pb-10">
|
<div class="pb-10">
|
||||||
|
|||||||
Reference in New Issue
Block a user