diff --git a/backend/open_webui/routers/folders.py b/backend/open_webui/routers/folders.py
index 4f6c6cd10f..9a3615080c 100644
--- a/backend/open_webui/routers/folders.py
+++ b/backend/open_webui/routers/folders.py
@@ -210,7 +210,8 @@ async def get_shared_folders(
async def get_folder_by_id(id: str, user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session)):
folder = await Folders.get_folder_by_id_and_user_id(id, user.id, db=db)
if folder:
- return folder
+ grants = await AccessGrants.get_grants_by_resource('folder', id, db=db)
+ return {**folder.model_dump(), 'access_grants': [g.model_dump() for g in grants]}
# Check shared access
folder = await Folders.get_folder_by_id(id, db=db)
diff --git a/src/lib/components/chat/Placeholder.svelte b/src/lib/components/chat/Placeholder.svelte
index 83f9a18a69..892bf7f0c9 100644
--- a/src/lib/components/chat/Placeholder.svelte
+++ b/src/lib/components/chat/Placeholder.svelte
@@ -74,8 +74,14 @@
$: models = selectedModels.map((id) => $_models.find((m) => m.id === id));
- // True when viewing a shared folder the current user doesn't own
- $: folderReadOnly = $selectedFolder != null && $selectedFolder.user_id !== $user?.id;
+ // True when viewing a shared folder the current user doesn't own AND lacks write access
+ $: folderReadOnly =
+ $selectedFolder != null &&
+ $selectedFolder.user_id !== $user?.id &&
+ $selectedFolder.permission !== 'write';
+
+ // True when the current user does NOT own this folder (hide management menus)
+ $: folderNotOwned = $selectedFolder != null && $selectedFolder.user_id !== $user?.id;
@@ -97,19 +103,19 @@
{#if $selectedFolder}
{
- await chats.set(await getChatList(localStorage.token, $currentChatPage));
- currentChatPage.set(1);
- }}
- onDelete={async () => {
- await chats.set(await getChatList(localStorage.token, $currentChatPage));
- currentChatPage.set(1);
+ folder={$selectedFolder}
+ readOnly={folderNotOwned}
+ onUpdate={async (folder) => {
+ await chats.set(await getChatList(localStorage.token, $currentChatPage));
+ currentChatPage.set(1);
+ }}
+ onDelete={async () => {
+ await chats.set(await getChatList(localStorage.token, $currentChatPage));
+ currentChatPage.set(1);
- selectedFolder.set(null);
- }}
- />
+ selectedFolder.set(null);
+ }}
+ />
{:else}
diff --git a/src/lib/components/layout/Sidebar/ChatItem.svelte b/src/lib/components/layout/Sidebar/ChatItem.svelte
index d4f9ca8f0d..498dffbd9f 100644
--- a/src/lib/components/layout/Sidebar/ChatItem.svelte
+++ b/src/lib/components/layout/Sidebar/ChatItem.svelte
@@ -529,6 +529,16 @@
on:focus={(e) => {}}
draggable="false"
>
+ {#if ownerUserId}
+
+
+
+ {/if}
+
{#if $activeChatIds.has(id)}
@@ -537,15 +547,6 @@
{/if}
- {#if ownerUserId}
-
-
-
- {/if}
{#if unread}
diff --git a/src/lib/components/layout/Sidebar/Folders/FolderShareModal.svelte b/src/lib/components/layout/Sidebar/Folders/FolderShareModal.svelte
index e2029b322c..318f7884e6 100644
--- a/src/lib/components/layout/Sidebar/Folders/FolderShareModal.svelte
+++ b/src/lib/components/layout/Sidebar/Folders/FolderShareModal.svelte
@@ -5,7 +5,7 @@
import Modal from '$lib/components/common/Modal.svelte';
import AccessControl from '$lib/components/workspace/common/AccessControl.svelte';
import XMark from '$lib/components/icons/XMark.svelte';
- import { updateFolderAccessById } from '$lib/apis/folders';
+ import { getFolderById, updateFolderAccessById } from '$lib/apis/folders';
import { user } from '$lib/stores';
type AccessGrant = {
@@ -19,11 +19,28 @@
export let folder: any = null;
let accessGrants: AccessGrant[] = [];
+ let loading = false;
- $: if (folder) {
- accessGrants = folder.access_grants ?? [];
+ // Fetch fresh folder data (with access_grants) when modal opens
+ $: if (show && folder?.id) {
+ loadAccessGrants();
}
+ const loadAccessGrants = async () => {
+ loading = true;
+ try {
+ const freshFolder = await getFolderById(localStorage.token, folder.id);
+ if (freshFolder) {
+ accessGrants = freshFolder.access_grants ?? [];
+ }
+ } catch (e) {
+ console.error('Failed to load folder access grants', e);
+ accessGrants = folder?.access_grants ?? [];
+ } finally {
+ loading = false;
+ }
+ };
+
const handleAccessChange = async () => {
if (!folder) return;
try {
diff --git a/src/lib/components/layout/Sidebar/RecursiveFolder.svelte b/src/lib/components/layout/Sidebar/RecursiveFolder.svelte
index 979a1029ef..0523de415e 100644
--- a/src/lib/components/layout/Sidebar/RecursiveFolder.svelte
+++ b/src/lib/components/layout/Sidebar/RecursiveFolder.svelte
@@ -549,7 +549,7 @@
});
if (folder) {
- await selectedFolder.set(folder);
+ await selectedFolder.set({ ...folders[folderId], ...folder });
}
await goto('/');
@@ -703,8 +703,8 @@
createdAt={chat.created_at}
updatedAt={chat.updated_at}
lastReadAt={chat.last_read_at}
- ownerName={chat.owner_name ?? null}
- ownerUserId={chat.owner_name ? chat.user_id : null}
+ ownerName={folders[folderId]?.shared ? (chat.owner_name ?? null) : null}
+ ownerUserId={folders[folderId]?.shared && chat.owner_name ? chat.user_id : null}
readonly={chat.user_id !== $user?.id}
{shiftKey}
on:change={(e) => {