feat(files): add shift+click quick delete to File Manager (#21044)

* feat(files): add shift+click quick delete to File Manager

Add shift+click functionality to FilesModal for rapid file deletion without confirmation dialogs.
Changes:
- Track Shift key state via keyboard event listeners
- When Shift is held, delete button bypasses confirmation and deletes immediately
- Visual feedback: delete icon turns red when Shift is held
- Optimized delete to remove file from local array instead of re-fetching entire list, enabling rapid successive deletions without UI flicker
This matches the quick delete pattern used in other workspace components like Tools, Prompts, and Models.

* Update FilesModal.svelte
This commit is contained in:
Classic298
2026-01-30 00:18:39 +04:00
committed by GitHub
parent baef422a28
commit ce8ed5b5ec
+41 -6
View File
@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { toast } from 'svelte-sonner'; import { toast } from 'svelte-sonner';
import { getContext } from 'svelte'; import { getContext, onMount, onDestroy } from 'svelte';
import type { Writable } from 'svelte/store'; import type { Writable } from 'svelte/store';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
@@ -36,6 +36,8 @@
let selectedFile: any = null; let selectedFile: any = null;
let showFileItemModal = false; let showFileItemModal = false;
let shiftKey = false;
const PAGE_SIZE = 50; const PAGE_SIZE = 50;
const formatFileSize = (bytes: number): string => { const formatFileSize = (bytes: number): string => {
@@ -121,7 +123,8 @@
try { try {
await deleteFileById(localStorage.token, fileId); await deleteFileById(localStorage.token, fileId);
toast.success($i18n.t('File deleted successfully.')); toast.success($i18n.t('File deleted successfully.'));
await searchHandler(); // Remove from local array instead of re-fetching to allow rapid deletion
files = files?.filter((f) => f.id !== fileId) ?? null;
} catch (error) { } catch (error) {
toast.error(`${error}`); toast.error(`${error}`);
} }
@@ -141,6 +144,34 @@
$: if (show) { $: if (show) {
searchHandler(); searchHandler();
} }
onMount(() => {
const onKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Shift') {
shiftKey = true;
}
};
const onKeyUp = (event: KeyboardEvent) => {
if (event.key === 'Shift') {
shiftKey = false;
}
};
const onBlur = () => {
shiftKey = false;
};
window.addEventListener('keydown', onKeyDown);
window.addEventListener('keyup', onKeyUp);
window.addEventListener('blur', onBlur);
return () => {
window.removeEventListener('keydown', onKeyDown);
window.removeEventListener('keyup', onKeyUp);
window.removeEventListener('blur', onBlur);
};
});
</script> </script>
<ConfirmDialog <ConfirmDialog
@@ -300,12 +331,16 @@
</div> </div>
<div class="flex justify-end pl-2.5 text-gray-600 dark:text-gray-300"> <div class="flex justify-end pl-2.5 text-gray-600 dark:text-gray-300">
<Tooltip content={$i18n.t('Delete File')}> <Tooltip content={shiftKey ? $i18n.t('Delete File') : $i18n.t('Delete File')}>
<button <button
class="self-center w-fit px-1 text-sm rounded-xl" class="self-center w-fit px-1 text-sm rounded-xl {shiftKey ? 'text-red-500' : ''}"
on:click|stopPropagation={() => { on:click|stopPropagation={() => {
selectedFileId = file.id; if (shiftKey) {
showDeleteConfirmDialog = true; deleteHandler(file.id);
} else {
selectedFileId = file.id;
showDeleteConfirmDialog = true;
}
}} }}
> >
<GarbageBin class="size-4" strokeWidth="1.5" /> <GarbageBin class="size-4" strokeWidth="1.5" />