From cc40085441203946236392b3251873242d6ee697 Mon Sep 17 00:00:00 2001 From: OpenCode Dev Date: Tue, 10 Feb 2026 10:59:36 +0000 Subject: [PATCH] feat: implement undo button to revert file changes and remove message from history - Modified handleUndoMessage in server.js to remove the undone message from session history - Added persistState() call to save the updated session state after undo - Message is now removed from UI when undo is completed - Works for opencode/build messages that are completed, errored, or cancelled --- chat/public/builder.js | 23 ++++++++++++++++++++++- chat/server.js | 10 ++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/chat/public/builder.js b/chat/public/builder.js index dcd00bc..a27a840 100644 --- a/chat/public/builder.js +++ b/chat/public/builder.js @@ -2153,7 +2153,13 @@ function renderMessages(session) { }); // Restore loading indicator visibility after all messages are rendered - if (loadingIndicator) { + // Only restore if the latest message is not done or error + const latestMsg = session.messages?.length > 0 + ? [...session.messages].reverse().find(msg => !msg.isBackgroundContinuation) + : null; + const shouldShowLoading = latestMsg && latestMsg.status !== 'done' && latestMsg.status !== 'error' && latestMsg.status !== 'cancelled'; + + if (loadingIndicator && shouldShowLoading) { loadingIndicator.style.visibility = ''; loadingIndicator.style.position = ''; // Ensure loading indicator is at the end of chat area @@ -2163,6 +2169,9 @@ function renderMessages(session) { // Move to end to ensure it's after all messages el.chatArea.appendChild(loadingIndicator); } + } else if (loadingIndicator && !shouldShowLoading) { + // Remove the loading indicator if message is done/error + loadingIndicator.remove(); } scrollChatToBottom(); @@ -3040,6 +3049,18 @@ function streamMessage(sessionId, messageId) { message.status = 'running'; // Keep loading indicator spinning during streaming - don't hide on first chunk + // Update loading indicator text to show we're now building + const loadingIndicator = document.getElementById('loading-indicator'); + if (loadingIndicator) { + const statusText = loadingIndicator.querySelector('.loading-status-text'); + const detailText = loadingIndicator.querySelector('.loading-detail-text'); + if (statusText && statusText.textContent === 'Starting build process') { + statusText.textContent = 'Building plugin'; + } + if (detailText) { + detailText.textContent = 'Generating code and files...'; + } + } // Re-render messages to show new content immediately renderMessages(session); diff --git a/chat/server.js b/chat/server.js index d7c9067..e40e85c 100644 --- a/chat/server.js +++ b/chat/server.js @@ -15920,6 +15920,16 @@ async function handleUndoMessage(req, res, sessionId, messageId, userId) { log('Cleared todos from undone message', { sessionId, messageId, clearedCount: todoCount }); } + // Remove the message from session history + const messageIndex = session.messages.findIndex(m => m.id === messageId); + if (messageIndex !== -1) { + session.messages.splice(messageIndex, 1); + log('Removed message from history', { sessionId, messageId, remainingMessages: session.messages.length }); + } + + // Persist the updated state + await persistState(); + log('Undo command completed', { sessionId, messageId }); sendJson(res, 200, { ok: true, message: 'Undo command sent successfully' }); } catch (error) {