fix: hide chat delete actions when the chat delete permission is disabled (#27714)

The chat delete endpoints gate on chat.delete for non-admins, but none of
the UI affordances that reach them were conditioned on it, so a user
without the permission is offered controls that always fail with
"Access prohibited".

Gates every entry point on the same condition the backend enforces,
matching the existing chat.share / chat.export / chat.import gates in the
same components:

- Sidebar chat menu (ChatMenu) Delete item — also covers the Search
  modal's menu, which reuses ChatMenu
- Sidebar Shift+hover inline Delete button (ChatItem)
- Sidebar hidden #delete-chat-button keyboard-shortcut target (ChatItem)
- Chat navbar menu Delete item (Navbar/Menu)
- Search modal Shift-held inline Delete button (SearchModal)
- Settings -> Data Controls -> Delete All Chats
- Settings -> Archived Chats per-row Delete
This commit is contained in:
G30
2026-08-10 23:24:02 -06:00
committed by GitHub
parent fe62934be7
commit a3d33b4cf3
6 changed files with 83 additions and 71 deletions
@@ -19,7 +19,7 @@
getArchivedChatList,
unarchiveAllChats
} from '$lib/apis/chats';
import { chatId, showSettings } from '$lib/stores';
import { chatId, showSettings, user } from '$lib/stores';
import { refreshChatList } from '$lib/stores/chatList';
import { formatNumber } from '$lib/utils';
import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
@@ -348,19 +348,21 @@
<UndoAction className="size-3.5" strokeWidth="1.5" />
</button>
</Tooltip>
<Tooltip content={$i18n.t('Delete Chat')}>
<button
class="rounded-lg p-1 text-gray-400 transition-colors hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300"
type="button"
aria-label={$i18n.t('Delete Chat')}
on:click={() => {
selectedChatId = chat.id;
showDeleteConfirmDialog = true;
}}
>
<Trash className="size-3.5" strokeWidth="1.5" />
</button>
</Tooltip>
{#if $user?.role === 'admin' || ($user?.permissions?.chat?.delete ?? true)}
<Tooltip content={$i18n.t('Delete Chat')}>
<button
class="rounded-lg p-1 text-gray-400 transition-colors hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300"
type="button"
aria-label={$i18n.t('Delete Chat')}
on:click={() => {
selectedChatId = chat.id;
showDeleteConfirmDialog = true;
}}
>
<Trash className="size-3.5" strokeWidth="1.5" />
</button>
</Tooltip>
{/if}
</div>
</div>
{/each}
@@ -216,20 +216,22 @@
</button>
</UserSettingRow>
<UserSettingRow
label={$i18n.t('Delete All Chats')}
description={$i18n.t('Permanently delete every chat after confirmation.')}
>
<button
class={actionButtonClass}
on:click={() => {
showDeleteConfirmDialog = true;
}}
type="button"
{#if $user?.role === 'admin' || ($user?.permissions?.chat?.delete ?? true)}
<UserSettingRow
label={$i18n.t('Delete All Chats')}
description={$i18n.t('Permanently delete every chat after confirmation.')}
>
{$i18n.t('Delete All')}
</button>
</UserSettingRow>
<button
class={actionButtonClass}
on:click={() => {
showDeleteConfirmDialog = true;
}}
type="button"
>
{$i18n.t('Delete All')}
</button>
</UserSettingRow>
{/if}
</UserSettingSection>
<UserSettingSection title={$i18n.t('Files')}>