← back to Exo
Ciaran/message deletion (#1409)
042999f728b68eae31056d9d99abbc32fe8963be · 2026-02-16 11:46:41 +0000 · ciaranbor
## Motivation
When a user deletes a message during an active streamed generation, it
can cause unexpected behavior. The delete confirmation text was also
misleading — it said "all responses after it" only for user messages,
which didn't accurately describe the behavior (all messages after the
deleted one are removed, regardless of role)
## Changes
- Prevent deletion during streaming: Disabled the delete button and
blocked handleDeleteClick when loading is true, with a visual indication
(dimmed button, cursor-not-allowed, tooltip change)
- Clarified delete confirmation text: Replaced role-specific wording
with a simpler, accurate message:
- Last message: "Delete this message?"
- Any other message: "Delete this message and all messages after it?"
## Why It Works
Guarding on the loading state at both the click handler and the button's
disabled attribute ensures no deletion can be triggered while a response
is being streamed
## Test Plan
### Manual Testing
- Verify the delete button is visually disabled and non-clickable while
a response is streaming
- Verify the tooltip shows "Cannot delete while generating" during
streaming
- Verify the last message shows "Delete this message?" confirmation
- Verify non-last messages show "Delete this message and all messages
after it?" confirmation
- Verify deletion works normally when not streaming
Files touched
M dashboard/src/lib/components/ChatMessages.svelte
Diff
commit 042999f728b68eae31056d9d99abbc32fe8963be
Author: ciaranbor <81697641+ciaranbor@users.noreply.github.com>
Date: Mon Feb 16 11:46:41 2026 +0000
Ciaran/message deletion (#1409)
## Motivation
When a user deletes a message during an active streamed generation, it
can cause unexpected behavior. The delete confirmation text was also
misleading — it said "all responses after it" only for user messages,
which didn't accurately describe the behavior (all messages after the
deleted one are removed, regardless of role)
## Changes
- Prevent deletion during streaming: Disabled the delete button and
blocked handleDeleteClick when loading is true, with a visual indication
(dimmed button, cursor-not-allowed, tooltip change)
- Clarified delete confirmation text: Replaced role-specific wording
with a simpler, accurate message:
- Last message: "Delete this message?"
- Any other message: "Delete this message and all messages after it?"
## Why It Works
Guarding on the loading state at both the click handler and the button's
disabled attribute ensures no deletion can be triggered while a response
is being streamed
## Test Plan
### Manual Testing
- Verify the delete button is visually disabled and non-clickable while
a response is streaming
- Verify the tooltip shows "Cannot delete while generating" during
streaming
- Verify the last message shows "Delete this message?" confirmation
- Verify non-last messages show "Delete this message and all messages
after it?" confirmation
- Verify deletion works normally when not streaming
---
dashboard/src/lib/components/ChatMessages.svelte | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/dashboard/src/lib/components/ChatMessages.svelte b/dashboard/src/lib/components/ChatMessages.svelte
index 46dfe46b..ba5322a7 100644
--- a/dashboard/src/lib/components/ChatMessages.svelte
+++ b/dashboard/src/lib/components/ChatMessages.svelte
@@ -225,6 +225,7 @@
}
function handleDeleteClick(messageId: string) {
+ if (loading) return;
deleteConfirmId = messageId;
}
@@ -255,7 +256,7 @@
</script>
<div class="flex flex-col gap-4 sm:gap-6 {className}">
- {#each messageList as message (message.id)}
+ {#each messageList as message, i (message.id)}
<div
class="group flex {message.role === 'user'
? 'justify-end'
@@ -317,9 +318,11 @@
<!-- Delete confirmation -->
<div class="bg-red-500/10 border border-red-500/30 rounded-lg p-3">
<p class="text-xs text-red-400 mb-3">
- Delete this message{message.role === "user"
- ? " and all responses after it"
- : ""}?
+ {#if i === messageList.length - 1}
+ Delete this message?
+ {:else}
+ Delete this message and all messages after it?
+ {/if}
</p>
<div class="flex gap-2 justify-end">
<button
@@ -751,8 +754,13 @@
<!-- Delete button -->
<button
onclick={() => handleDeleteClick(message.id)}
- class="p-1.5 text-exo-light-gray hover:text-red-400 transition-colors rounded hover:bg-red-500/10 cursor-pointer"
- title="Delete message"
+ disabled={loading}
+ class="p-1.5 transition-colors rounded {loading
+ ? 'text-exo-light-gray/30 cursor-not-allowed'
+ : 'text-exo-light-gray hover:text-red-400 hover:bg-red-500/10 cursor-pointer'}"
+ title={loading
+ ? "Cannot delete while generating"
+ : "Delete message"}
>
<svg
class="w-3.5 h-3.5"
← b61dc2eb Prevent image editing without image input (#1410)
·
back to Exo
·
fix: PlaceInstanceParams broken field validator 2d8bfc2e →