Commit f5892ca5a for llama.cpp

commit f5892ca5ad32685d0b1e6a54bd3e423756ea8077
Author: Aleksander Grygier <aleksander.grygier@gmail.com>
Date:   Tue Oct 27 06:45:53 2026 +0100

    ui: use shared confirmation dialog for conversation deletion (#31187)

    Extract the keyboard-shortcut delete confirmation into DialogConversationDelete
    and reuse it in the sidebar and mobile search page instead of the native
    window.confirm prompt.

    Assisted-by: Claude (Opus 5.5 Medium)

diff --git a/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreenDialogsAndAlerts.svelte b/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreenDialogsAndAlerts.svelte
index feba9ee35..d8ff0d2ee 100644
--- a/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreenDialogsAndAlerts.svelte
+++ b/tools/ui/src/lib/components/app/chat/ChatScreen/ChatScreenDialogsAndAlerts.svelte
@@ -1,8 +1,7 @@
 <script lang="ts">
-	import { Trash2 } from '@lucide/svelte';
 	import {
 		DialogChatError,
-		DialogConfirmation,
+		DialogConversationDelete,
 		DialogEmptyFileAlert,
 		DialogFileUploadError
 	} from '$lib/components/app';
@@ -24,16 +23,10 @@
 	fileErrorData={fileUpload.fileErrorData}
 />

-<DialogConfirmation
+<DialogConversationDelete
 	bind:open={showDeleteDialog}
-	cancelText="Cancel"
-	confirmText="Delete"
-	description="Are you sure you want to delete this conversation? This action cannot be undone and will permanently remove all messages in this conversation."
-	icon={Trash2}
 	onCancel={() => (showDeleteDialog = false)}
 	onConfirm={handleDeleteConfirm}
-	title="Delete Conversation"
-	variant="destructive"
 />

 <DialogEmptyFileAlert
diff --git a/tools/ui/src/lib/components/app/dialogs/DialogConversationDelete.svelte b/tools/ui/src/lib/components/app/dialogs/DialogConversationDelete.svelte
new file mode 100644
index 000000000..b25259f63
--- /dev/null
+++ b/tools/ui/src/lib/components/app/dialogs/DialogConversationDelete.svelte
@@ -0,0 +1,24 @@
+<script lang="ts">
+	import { Trash2 } from '@lucide/svelte';
+	import { DialogConfirmation } from '$lib/components/app';
+
+	interface Props {
+		open: boolean;
+		onConfirm: () => void;
+		onCancel: () => void;
+	}
+
+	let { onCancel, onConfirm, open = $bindable() }: Props = $props();
+</script>
+
+<DialogConfirmation
+	bind:open
+	cancelText="Cancel"
+	confirmText="Delete"
+	description="Are you sure you want to delete this conversation? This action cannot be undone and will permanently remove all messages in this conversation."
+	icon={Trash2}
+	{onCancel}
+	{onConfirm}
+	title="Delete Conversation"
+	variant="destructive"
+/>
diff --git a/tools/ui/src/lib/components/app/dialogs/index.ts b/tools/ui/src/lib/components/app/dialogs/index.ts
index 5c6a56f00..ff287ec18 100644
--- a/tools/ui/src/lib/components/app/dialogs/index.ts
+++ b/tools/ui/src/lib/components/app/dialogs/index.ts
@@ -119,6 +119,23 @@ export { default as DialogConfirmation } from './DialogConfirmation.svelte';
  */
 export { default as DialogConfirmDownload } from './DialogConfirmDownload.svelte';

+/**
+ * **DialogConversationDelete** - Confirm deleting a conversation
+ *
+ * Destructive confirmation shared by every conversation delete entry point
+ * (keyboard shortcut, sidebar, mobile search).
+ *
+ * @example
+ * ```svelte
+ * <DialogConversationDelete
+ *   bind:open={showDelete}
+ *   onConfirm={handleDelete}
+ *   onCancel={() => (showDelete = false)}
+ * />
+ * ```
+ */
+export { default as DialogConversationDelete } from './DialogConversationDelete.svelte';
+
 /**
  * **DialogConversationRename** - Rename a conversation
  *
diff --git a/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte b/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte
index 9fb451361..4430de50c 100644
--- a/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte
+++ b/tools/ui/src/lib/components/app/navigation/SidebarNavigation/SidebarNavigation.svelte
@@ -4,6 +4,7 @@
 	import { page } from '$app/state';
 	import {
 		ActionIcon,
+		DialogConversationDelete,
 		DialogConversationRename,
 		DialogDiscoverModels,
 		DialogMcpServers,
@@ -280,20 +281,32 @@
 		renameOriginalTitle = '';
 	}

-	async function handleDeleteConversation(id: string) {
+	let deleteDialogOpen = $state(false);
+	let deleteTargetId = $state<string | null>(null);
+
+	function handleDeleteConversation(id: string) {
 		const conversation = conversationsStore.conversations.find((conv) => conv.id === id);

 		if (!conversation) return;

-		const confirmed = window.confirm(
-			`Delete "${conversation.name}"? This action cannot be undone.`
-		);
+		deleteTargetId = conversation.id;
+		deleteDialogOpen = true;
+	}
+
+	async function handleDeleteConfirm() {
+		const id = deleteTargetId;

-		if (!confirmed) return;
+		deleteDialogOpen = false;
+
+		if (!id) return;

 		await conversationsStore.deleteConversation(id, { deleteWithForks: false });
 	}

+	function handleDeleteCancel() {
+		deleteDialogOpen = false;
+	}
+
 	function handleStopGeneration(id: string) {
 		chatStore.stopGenerationForChat(id);
 	}
@@ -617,6 +630,12 @@
 	onConfirm={handleRenameConfirm}
 />

+<DialogConversationDelete
+	bind:open={deleteDialogOpen}
+	onCancel={handleDeleteCancel}
+	onConfirm={handleDeleteConfirm}
+/>
+
 <DialogSettingsChat bind:open={settingsDialogOpen} />

 <DialogMcpServers bind:open={mcpDialogOpen} />
diff --git a/tools/ui/src/routes/search/+page.svelte b/tools/ui/src/routes/search/+page.svelte
index 5b68d267f..cd4626881 100644
--- a/tools/ui/src/routes/search/+page.svelte
+++ b/tools/ui/src/routes/search/+page.svelte
@@ -2,7 +2,11 @@
 	import { browser } from '$app/environment';
 	import { goto } from '$app/navigation';
 	import { page } from '$app/state';
-	import { SearchInput, SidebarNavigationSearchResults } from '$lib/components/app';
+	import {
+		DialogConversationDelete,
+		SearchInput,
+		SidebarNavigationSearchResults
+	} from '$lib/components/app';
 	import { ROUTES } from '$lib/constants';
 	import { RouterService } from '$lib/services/router.service';
 	import { chatStore, conversationsStore, deviceStore } from '$lib/stores';
@@ -44,20 +48,32 @@
 		}
 	}

-	async function handleDeleteConversation(id: string) {
+	let deleteDialogOpen = $state(false);
+	let deleteTargetId = $state<string | null>(null);
+
+	function handleDeleteConversation(id: string) {
 		const conversation = conversationsStore.conversations.find((c) => c.id === id);

 		if (!conversation) return;

-		const confirmed = window.confirm(
-			`Delete "${conversation.name}"? This action cannot be undone.`
-		);
+		deleteTargetId = conversation.id;
+		deleteDialogOpen = true;
+	}
+
+	async function handleDeleteConfirm() {
+		const id = deleteTargetId;
+
+		deleteDialogOpen = false;

-		if (!confirmed) return;
+		if (!id) return;

 		await conversationsStore.deleteConversation(id, { deleteWithForks: false });
 	}

+	function handleDeleteCancel() {
+		deleteDialogOpen = false;
+	}
+
 	function handleStopGeneration(id: string) {
 		chatStore.stopGenerationForChat(id);
 	}
@@ -96,3 +112,9 @@
 		{searchQuery}
 	/>
 </div>
+
+<DialogConversationDelete
+	bind:open={deleteDialogOpen}
+	onCancel={handleDeleteCancel}
+	onConfirm={handleDeleteConfirm}
+/>