From b70c0f36c0f5bbfc2a767429984d6fba1a7bb26c Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 4 Sep 2025 02:50:50 +0400 Subject: [PATCH] enh: emoji folder icon --- backend/open_webui/models/folders.py | 17 +++++++- backend/open_webui/routers/folders.py | 21 ++++++---- src/lib/apis/folders/index.ts | 3 +- .../channel/Messages/Message.svelte | 26 ++++-------- .../chat/Placeholder/FolderTitle.svelte | 41 +++++++++++++++++-- src/lib/components/common/Emoji.svelte | 20 +++++++++ .../EmojiPicker.svelte} | 0 src/lib/components/common/Folder.svelte | 6 +-- src/lib/components/layout/Sidebar.svelte | 2 +- .../layout/Sidebar/RecursiveFolder.svelte | 25 +++++++++-- 10 files changed, 119 insertions(+), 42 deletions(-) create mode 100644 src/lib/components/common/Emoji.svelte rename src/lib/components/{channel/Messages/Message/ReactionPicker.svelte => common/EmojiPicker.svelte} (100%) diff --git a/backend/open_webui/models/folders.py b/backend/open_webui/models/folders.py index 15deecbf42..c876645750 100644 --- a/backend/open_webui/models/folders.py +++ b/backend/open_webui/models/folders.py @@ -58,6 +58,14 @@ class FolderModel(BaseModel): class FolderForm(BaseModel): name: str data: Optional[dict] = None + meta: Optional[dict] = None + model_config = ConfigDict(extra="allow") + + +class FolderUpdateForm(BaseModel): + name: Optional[str] = None + data: Optional[dict] = None + meta: Optional[dict] = None model_config = ConfigDict(extra="allow") @@ -191,7 +199,7 @@ class FolderTable: return def update_folder_by_id_and_user_id( - self, id: str, user_id: str, form_data: FolderForm + self, id: str, user_id: str, form_data: FolderUpdateForm ) -> Optional[FolderModel]: try: with get_db() as db: @@ -222,8 +230,13 @@ class FolderTable: **form_data["data"], } - folder.updated_at = int(time.time()) + if "meta" in form_data: + folder.meta = { + **(folder.meta or {}), + **form_data["meta"], + } + folder.updated_at = int(time.time()) db.commit() return FolderModel.model_validate(folder) diff --git a/backend/open_webui/routers/folders.py b/backend/open_webui/routers/folders.py index e419989e46..cd333d9071 100644 --- a/backend/open_webui/routers/folders.py +++ b/backend/open_webui/routers/folders.py @@ -10,6 +10,7 @@ import mimetypes from open_webui.models.folders import ( FolderForm, + FolderUpdateForm, FolderModel, Folders, ) @@ -113,22 +114,24 @@ async def get_folder_by_id(id: str, user=Depends(get_verified_user)): @router.post("/{id}/update") async def update_folder_name_by_id( - id: str, form_data: FolderForm, user=Depends(get_verified_user) + id: str, form_data: FolderUpdateForm, user=Depends(get_verified_user) ): folder = Folders.get_folder_by_id_and_user_id(id, user.id) if folder: - existing_folder = Folders.get_folder_by_parent_id_and_user_id_and_name( - folder.parent_id, user.id, form_data.name - ) - if existing_folder and existing_folder.id != id: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=ERROR_MESSAGES.DEFAULT("Folder already exists"), + + if form_data.name is not None: + # Check if folder with same name exists + existing_folder = Folders.get_folder_by_parent_id_and_user_id_and_name( + folder.parent_id, user.id, form_data.name ) + if existing_folder and existing_folder.id != id: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=ERROR_MESSAGES.DEFAULT("Folder already exists"), + ) try: folder = Folders.update_folder_by_id_and_user_id(id, user.id, form_data) - return folder except Exception as e: log.exception(e) diff --git a/src/lib/apis/folders/index.ts b/src/lib/apis/folders/index.ts index dc2d8bbf18..0faa547141 100644 --- a/src/lib/apis/folders/index.ts +++ b/src/lib/apis/folders/index.ts @@ -1,8 +1,9 @@ import { WEBUI_API_BASE_URL } from '$lib/constants'; type FolderForm = { - name: string; + name?: string; data?: Record; + meta?: Record; }; export const createNewFolder = async (token: string, folderForm: FolderForm) => { diff --git a/src/lib/components/channel/Messages/Message.svelte b/src/lib/components/channel/Messages/Message.svelte index 075530d608..649529a6f9 100644 --- a/src/lib/components/channel/Messages/Message.svelte +++ b/src/lib/components/channel/Messages/Message.svelte @@ -30,9 +30,10 @@ import ProfilePreview from './Message/ProfilePreview.svelte'; import ChatBubbleOvalEllipsis from '$lib/components/icons/ChatBubble.svelte'; import FaceSmile from '$lib/components/icons/FaceSmile.svelte'; - import ReactionPicker from './Message/ReactionPicker.svelte'; + import EmojiPicker from '$lib/components/common/EmojiPicker.svelte'; import ChevronRight from '$lib/components/icons/ChevronRight.svelte'; import { formatDate } from '$lib/utils'; + import Emoji from '$lib/components/common/Emoji.svelte'; export let message; export let showUserProfile = true; @@ -74,7 +75,7 @@
- (showButtons = false)} onSubmit={(name) => { showButtons = false; @@ -91,7 +92,7 @@ - + {#if !thread} @@ -275,20 +276,7 @@ onReaction(reaction.name); }} > - {#if $shortCodesToEmojis[reaction.name]} - {reaction.name} - {:else} -
- {reaction.name} -
- {/if} + {#if reaction.user_ids.length > 0}
@@ -299,7 +287,7 @@ {/each} - { onReaction(name); }} @@ -311,7 +299,7 @@
- +
{/if} diff --git a/src/lib/components/chat/Placeholder/FolderTitle.svelte b/src/lib/components/chat/Placeholder/FolderTitle.svelte index 18f4bd0c96..a8e2004ef0 100644 --- a/src/lib/components/chat/Placeholder/FolderTitle.svelte +++ b/src/lib/components/chat/Placeholder/FolderTitle.svelte @@ -21,6 +21,8 @@ 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'; + import Emoji from '$lib/components/common/Emoji.svelte'; + import EmojiPicker from '$lib/components/common/EmojiPicker.svelte'; export let folder = null; @@ -63,6 +65,25 @@ } }; + const updateIconHandler = async (iconName) => { + const res = await updateFolderById(localStorage.token, folder.id, { + meta: { + icon: iconName + } + }).catch((error) => { + toast.error(`${error}`); + return null; + }); + + if (res) { + folder.meta = { ...folder.meta, icon: iconName }; + + 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}`); @@ -116,9 +137,23 @@
-
- -
+ {}} + onSubmit={(name) => { + console.log(name); + updateIconHandler(name); + }} + > + +
{folder.name} diff --git a/src/lib/components/common/Emoji.svelte b/src/lib/components/common/Emoji.svelte new file mode 100644 index 0000000000..be1fe36475 --- /dev/null +++ b/src/lib/components/common/Emoji.svelte @@ -0,0 +1,20 @@ + + +{#if $shortCodesToEmojis[shortCode]} + {shortCode} +{:else} +
+ {shortCode} +
+{/if} diff --git a/src/lib/components/channel/Messages/Message/ReactionPicker.svelte b/src/lib/components/common/EmojiPicker.svelte similarity index 100% rename from src/lib/components/channel/Messages/Message/ReactionPicker.svelte rename to src/lib/components/common/EmojiPicker.svelte diff --git a/src/lib/components/common/Folder.svelte b/src/lib/components/common/Folder.svelte index dc663c191d..6c3d6605bd 100644 --- a/src/lib/components/common/Folder.svelte +++ b/src/lib/components/common/Folder.svelte @@ -142,11 +142,11 @@ >