Skip to content

Commit ce8ed5b

Browse files
authored
feat(files): add shift+click quick delete to File Manager (open-webui#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
1 parent baef422 commit ce8ed5b

1 file changed

Lines changed: 41 additions & 6 deletions

File tree

src/lib/components/layout/FilesModal.svelte

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { toast } from 'svelte-sonner';
3-
import { getContext } from 'svelte';
3+
import { getContext, onMount, onDestroy } from 'svelte';
44
import type { Writable } from 'svelte/store';
55
import dayjs from 'dayjs';
66
@@ -36,6 +36,8 @@
3636
let selectedFile: any = null;
3737
let showFileItemModal = false;
3838
39+
let shiftKey = false;
40+
3941
const PAGE_SIZE = 50;
4042
4143
const formatFileSize = (bytes: number): string => {
@@ -121,7 +123,8 @@
121123
try {
122124
await deleteFileById(localStorage.token, fileId);
123125
toast.success($i18n.t('File deleted successfully.'));
124-
await searchHandler();
126+
// Remove from local array instead of re-fetching to allow rapid deletion
127+
files = files?.filter((f) => f.id !== fileId) ?? null;
125128
} catch (error) {
126129
toast.error(`${error}`);
127130
}
@@ -141,6 +144,34 @@
141144
$: if (show) {
142145
searchHandler();
143146
}
147+
148+
onMount(() => {
149+
const onKeyDown = (event: KeyboardEvent) => {
150+
if (event.key === 'Shift') {
151+
shiftKey = true;
152+
}
153+
};
154+
155+
const onKeyUp = (event: KeyboardEvent) => {
156+
if (event.key === 'Shift') {
157+
shiftKey = false;
158+
}
159+
};
160+
161+
const onBlur = () => {
162+
shiftKey = false;
163+
};
164+
165+
window.addEventListener('keydown', onKeyDown);
166+
window.addEventListener('keyup', onKeyUp);
167+
window.addEventListener('blur', onBlur);
168+
169+
return () => {
170+
window.removeEventListener('keydown', onKeyDown);
171+
window.removeEventListener('keyup', onKeyUp);
172+
window.removeEventListener('blur', onBlur);
173+
};
174+
});
144175
</script>
145176

146177
<ConfirmDialog
@@ -300,12 +331,16 @@
300331
</div>
301332

302333
<div class="flex justify-end pl-2.5 text-gray-600 dark:text-gray-300">
303-
<Tooltip content={$i18n.t('Delete File')}>
334+
<Tooltip content={shiftKey ? $i18n.t('Delete File') : $i18n.t('Delete File')}>
304335
<button
305-
class="self-center w-fit px-1 text-sm rounded-xl"
336+
class="self-center w-fit px-1 text-sm rounded-xl {shiftKey ? 'text-red-500' : ''}"
306337
on:click|stopPropagation={() => {
307-
selectedFileId = file.id;
308-
showDeleteConfirmDialog = true;
338+
if (shiftKey) {
339+
deleteHandler(file.id);
340+
} else {
341+
selectedFileId = file.id;
342+
showDeleteConfirmDialog = true;
343+
}
309344
}}
310345
>
311346
<GarbageBin class="size-4" strokeWidth="1.5" />

0 commit comments

Comments
 (0)