Skip to content

Commit 917b2cc

Browse files
Simplify edit panel (#5488)
fix
1 parent 15f3876 commit 917b2cc

File tree

20 files changed

+66
-250
lines changed

20 files changed

+66
-250
lines changed

src/core/webview/__tests__/ClineProvider.spec.ts

Lines changed: 21 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ vi.mock("vscode", () => ({
145145
},
146146
window: {
147147
showInformationMessage: vi.fn(),
148+
showWarningMessage: vi.fn(),
148149
showErrorMessage: vi.fn(),
149150
},
150151
workspace: {
@@ -1289,14 +1290,14 @@ describe("ClineProvider", () => {
12891290

12901291
describe("editMessage", () => {
12911292
beforeEach(async () => {
1292-
// Mock window.showInformationMessage
1293-
;(vscode.window.showInformationMessage as any) = vi.fn()
1293+
// Mock window.showWarningMessage
1294+
;(vscode.window.showWarningMessage as any) = vi.fn()
12941295
await provider.resolveWebviewView(mockWebviewView)
12951296
})
12961297

1297-
test('handles "No, just edit this one" edit correctly', async () => {
1298-
// Mock user selecting "No, just edit this one"
1299-
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.edit_just_this_message")
1298+
test('handles "Proceed" edit correctly', async () => {
1299+
// Mock user selecting "Proceed" - need to use the localized string key
1300+
;(vscode.window.showWarningMessage as any).mockResolvedValue("confirmation.proceed")
13001301

13011302
// Setup mock messages
13021303
const mockMessages = [
@@ -1345,20 +1346,13 @@ describe("ClineProvider", () => {
13451346
editedMessageContent: "Edited message content",
13461347
})
13471348

1348-
// Verify correct messages were kept
1349-
expect(mockCline.overwriteClineMessages).toHaveBeenCalledWith([
1350-
mockMessages[0],
1351-
mockMessages[1],
1352-
mockMessages[4],
1353-
mockMessages[5],
1354-
])
1349+
// Verify correct messages were kept (only messages before the edited one)
1350+
expect(mockCline.overwriteClineMessages).toHaveBeenCalledWith([mockMessages[0], mockMessages[1]])
13551351

1356-
// Verify correct API messages were kept
1352+
// Verify correct API messages were kept (only messages before the edited one)
13571353
expect(mockCline.overwriteApiConversationHistory).toHaveBeenCalledWith([
13581354
mockApiHistory[0],
13591355
mockApiHistory[1],
1360-
mockApiHistory[4],
1361-
mockApiHistory[5],
13621356
])
13631357

13641358
// Verify handleWebviewAskResponse was called with the edited content
@@ -1368,103 +1362,6 @@ describe("ClineProvider", () => {
13681362
undefined,
13691363
)
13701364
})
1371-
1372-
test('handles "Yes" (edit and delete subsequent) correctly', async () => {
1373-
// Mock user selecting "Yes"
1374-
;(vscode.window.showInformationMessage as any).mockResolvedValue(
1375-
"confirmation.edit_this_and_delete_subsequent",
1376-
)
1377-
1378-
// Setup mock messages
1379-
const mockMessages = [
1380-
{ ts: 1000, type: "say", say: "user_feedback" },
1381-
{ ts: 2000, type: "say", say: "text", value: 3000 }, // Message to edit
1382-
{ ts: 3000, type: "say", say: "user_feedback" },
1383-
{ ts: 4000, type: "say", say: "user_feedback" },
1384-
] as ClineMessage[]
1385-
1386-
const mockApiHistory = [
1387-
{ ts: 1000 },
1388-
{ ts: 2000 },
1389-
{ ts: 3000 },
1390-
{ ts: 4000 },
1391-
] as (Anthropic.MessageParam & {
1392-
ts?: number
1393-
})[]
1394-
1395-
// Setup Cline instance with auto-mock from the top of the file
1396-
const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
1397-
mockCline.clineMessages = mockMessages
1398-
mockCline.apiConversationHistory = mockApiHistory
1399-
1400-
// Explicitly mock the overwrite methods since they're not being called in the tests
1401-
mockCline.overwriteClineMessages = vi.fn()
1402-
mockCline.overwriteApiConversationHistory = vi.fn()
1403-
mockCline.handleWebviewAskResponse = vi.fn()
1404-
1405-
await provider.addClineToStack(mockCline)
1406-
1407-
// Mock getTaskWithId
1408-
;(provider as any).getTaskWithId = vi.fn().mockResolvedValue({
1409-
historyItem: { id: "test-task-id" },
1410-
})
1411-
1412-
// Trigger message edit
1413-
// Get the message handler function that was registered with the webview
1414-
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as any).mock.calls[0][0]
1415-
1416-
// Call the message handler with a submitEditedMessage message
1417-
await messageHandler({
1418-
type: "submitEditedMessage",
1419-
value: 3000,
1420-
editedMessageContent: "Edited message content",
1421-
})
1422-
1423-
// Verify only messages before the edited message were kept
1424-
expect(mockCline.overwriteClineMessages).toHaveBeenCalledWith([mockMessages[0]])
1425-
1426-
// Verify only API messages before the edited message were kept
1427-
expect(mockCline.overwriteApiConversationHistory).toHaveBeenCalledWith([mockApiHistory[0]])
1428-
1429-
// Verify handleWebviewAskResponse was called with the edited content
1430-
expect(mockCline.handleWebviewAskResponse).toHaveBeenCalledWith(
1431-
"messageResponse",
1432-
"Edited message content",
1433-
undefined,
1434-
)
1435-
})
1436-
1437-
test("handles Cancel correctly", async () => {
1438-
// Mock user selecting "Cancel"
1439-
;(vscode.window.showInformationMessage as any).mockResolvedValue("Cancel")
1440-
1441-
// Setup Cline instance with auto-mock from the top of the file
1442-
const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
1443-
mockCline.clineMessages = [{ ts: 1000 }, { ts: 2000 }] as ClineMessage[]
1444-
mockCline.apiConversationHistory = [{ ts: 1000 }, { ts: 2000 }] as (Anthropic.MessageParam & {
1445-
ts?: number
1446-
})[]
1447-
1448-
// Explicitly mock the overwrite methods since they're not being called in the tests
1449-
mockCline.overwriteClineMessages = vi.fn()
1450-
mockCline.overwriteApiConversationHistory = vi.fn()
1451-
mockCline.handleWebviewAskResponse = vi.fn()
1452-
1453-
await provider.addClineToStack(mockCline)
1454-
1455-
// Trigger message edit
1456-
const messageHandler = (mockWebviewView.webview.onDidReceiveMessage as any).mock.calls[0][0]
1457-
await messageHandler({
1458-
type: "submitEditedMessage",
1459-
value: 2000,
1460-
editedMessageContent: "Edited message content",
1461-
})
1462-
1463-
// Verify no messages were edited or deleted
1464-
expect(mockCline.overwriteClineMessages).not.toHaveBeenCalled()
1465-
expect(mockCline.overwriteApiConversationHistory).not.toHaveBeenCalled()
1466-
expect(mockCline.handleWebviewAskResponse).not.toHaveBeenCalled()
1467-
})
14681365
})
14691366

14701367
describe("getSystemPrompt", () => {
@@ -2813,7 +2710,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
28132710
})
28142711

28152712
test("handles editing messages containing images", async () => {
2816-
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.edit_just_this_message")
2713+
;(vscode.window.showWarningMessage as any).mockResolvedValue("confirmation.proceed")
28172714

28182715
const mockMessages = [
28192716
{ ts: 1000, type: "say", say: "user_feedback", text: "Original message" },
@@ -2858,7 +2755,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
28582755
})
28592756

28602757
test("handles editing messages with file attachments", async () => {
2861-
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.edit_just_this_message")
2758+
;(vscode.window.showWarningMessage as any).mockResolvedValue("confirmation.proceed")
28622759

28632760
const mockMessages = [
28642761
{ ts: 1000, type: "say", say: "user_feedback", text: "Original message" },
@@ -2908,7 +2805,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
29082805
})
29092806

29102807
test("handles network timeout during edit submission", async () => {
2911-
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.edit_just_this_message")
2808+
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.proceed")
29122809

29132810
const mockCline = new Task(defaultTaskOptions)
29142811
mockCline.clineMessages = [
@@ -2940,7 +2837,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
29402837
})
29412838

29422839
test("handles connection drops during edit operation", async () => {
2943-
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.edit_just_this_message")
2840+
;(vscode.window.showWarningMessage as any).mockResolvedValue("confirmation.proceed")
29442841

29452842
const mockCline = new Task(defaultTaskOptions)
29462843
mockCline.clineMessages = [
@@ -2979,7 +2876,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
29792876
})
29802877

29812878
test("handles race conditions with simultaneous edits", async () => {
2982-
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.edit_just_this_message")
2879+
;(vscode.window.showWarningMessage as any).mockResolvedValue("confirmation.proceed")
29832880

29842881
const mockCline = new Task(defaultTaskOptions)
29852882
mockCline.clineMessages = [
@@ -3043,7 +2940,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
30432940
})
30442941

30452942
test("handles authorization failures during edit", async () => {
3046-
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.edit_just_this_message")
2943+
;(vscode.window.showWarningMessage as any).mockResolvedValue("confirmation.proceed")
30472944

30482945
const mockCline = new Task(defaultTaskOptions)
30492946
mockCline.clineMessages = [
@@ -3161,7 +3058,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
31613058
})
31623059

31633060
test("handles edit operations on deleted messages", async () => {
3164-
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.edit_just_this_message")
3061+
;(vscode.window.showWarningMessage as any).mockResolvedValue("confirmation.proceed")
31653062

31663063
const mockCline = new Task(defaultTaskOptions)
31673064
mockCline.clineMessages = [
@@ -3187,7 +3084,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
31873084
})
31883085

31893086
// Should show confirmation dialog but not perform any operations
3190-
expect(vscode.window.showInformationMessage).toHaveBeenCalled()
3087+
expect(vscode.window.showWarningMessage).toHaveBeenCalled()
31913088
expect(mockCline.overwriteClineMessages).not.toHaveBeenCalled()
31923089
expect(mockCline.handleWebviewAskResponse).not.toHaveBeenCalled()
31933090
})
@@ -3231,7 +3128,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
32313128
})
32323129

32333130
test("validates proper cleanup during failed edit operations", async () => {
3234-
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.edit_just_this_message")
3131+
;(vscode.window.showWarningMessage as any).mockResolvedValue("confirmation.proceed")
32353132

32363133
const mockCline = new Task(defaultTaskOptions)
32373134
mockCline.clineMessages = [
@@ -3311,7 +3208,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
33113208
})
33123209

33133210
test("handles editing messages with large text content", async () => {
3314-
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.edit_just_this_message")
3211+
;(vscode.window.showWarningMessage as any).mockResolvedValue("confirmation.proceed")
33153212

33163213
// Create a large message (10KB of text)
33173214
const largeText = "A".repeat(10000)
@@ -3419,7 +3316,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
34193316

34203317
test("handles user cancellation gracefully", async () => {
34213318
// Mock user canceling the operation
3422-
;(vscode.window.showInformationMessage as any).mockResolvedValue(undefined)
3319+
;(vscode.window.showWarningMessage as any).mockResolvedValue(undefined)
34233320

34243321
const mockCline = new Task(defaultTaskOptions)
34253322
mockCline.clineMessages = [
@@ -3485,7 +3382,7 @@ describe("ClineProvider - Comprehensive Edit/Delete Edge Cases", () => {
34853382
})
34863383

34873384
test("handles messages with future timestamps", async () => {
3488-
;(vscode.window.showInformationMessage as any).mockResolvedValue("confirmation.edit_just_this_message")
3385+
;(vscode.window.showWarningMessage as any).mockResolvedValue("confirmation.proceed")
34893386

34903387
const futureTimestamp = Date.now() + 100000 // Future timestamp
34913388
const mockCline = new Task(defaultTaskOptions)

src/core/webview/webviewMessageHandler.ts

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -193,32 +193,23 @@ export const webviewMessageHandler = async (
193193
* Handles message editing operations with user confirmation
194194
*/
195195
const handleEditOperation = async (messageTs: number, editedContent: string): Promise<void> => {
196-
const options = [
197-
t("common:confirmation.edit_this_and_delete_subsequent"),
198-
t("common:confirmation.edit_just_this_message"),
199-
]
200-
201-
const answer = await vscode.window.showInformationMessage(
202-
t("common:confirmation.edit_message"),
196+
const answer = await vscode.window.showWarningMessage(
197+
t("common:confirmation.edit_warning"),
203198
{ modal: true },
204-
...options,
199+
t("common:confirmation.proceed"),
205200
)
206201

207-
// Only proceed if user selected one of the options and we have a current cline
208-
if (answer && options.includes(answer) && provider.getCurrentCline()) {
202+
// Only proceed if user selected "Proceed" and we have a current cline
203+
if (answer === t("common:confirmation.proceed") && provider.getCurrentCline()) {
209204
const currentCline = provider.getCurrentCline()!
205+
206+
// Use findMessageIndices to find messages based on timestamp
210207
const { messageIndex, apiConversationHistoryIndex } = findMessageIndices(messageTs, currentCline)
211208

212209
if (messageIndex !== -1) {
213210
try {
214-
// Check which option the user selected
215-
if (answer === options[0]) {
216-
// Edit this message and delete subsequent
217-
await removeMessagesThisAndSubsequent(currentCline, messageIndex, apiConversationHistoryIndex)
218-
} else if (answer === options[1]) {
219-
// Edit just this message
220-
await removeMessagesJustThis(currentCline, messageIndex, apiConversationHistoryIndex)
221-
}
211+
// Edit this message and delete subsequent
212+
await removeMessagesThisAndSubsequent(currentCline, messageIndex, apiConversationHistoryIndex)
222213

223214
// Process the edited message as a regular user message
224215
// This will add it to the conversation and trigger an AI response

src/i18n/locales/ca/common.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@
2323
"delete_config_profile": "Estàs segur que vols eliminar aquest perfil de configuració?",
2424
"delete_custom_mode_with_rules": "Esteu segur que voleu suprimir aquest mode {scope}?\n\nAixò també suprimirà la carpeta de regles associada a:\n{rulesFolderPath}",
2525
"delete_message": "Què vols eliminar?",
26-
"edit_message": "Eliminar tots els missatges després d'aquest?",
26+
"edit_warning": "Editar aquest missatge eliminarà tots els missatges posteriors de la conversa. Vols continuar?",
2727
"delete_just_this_message": "Només aquest missatge",
28-
"edit_just_this_message": "No, només editar aquest",
2928
"delete_this_and_subsequent": "Aquest i tots els missatges posteriors",
30-
"edit_this_and_delete_subsequent": ""
29+
"proceed": "Continuar"
3130
},
3231
"errors": {
3332
"invalid_data_uri": "Format d'URI de dades no vàlid",
@@ -111,13 +110,11 @@
111110
"answers": {
112111
"yes": "",
113112
"no": "No",
114-
"cancel": "Cancel·lar",
115113
"remove": "Eliminar",
116114
"keep": "Mantenir"
117115
},
118116
"buttons": {
119117
"save": "Desar",
120-
"cancel": "Cancel·lar",
121118
"edit": "Editar"
122119
},
123120
"tasks": {
@@ -171,7 +168,6 @@
171168
"title": "Suprimeix el mode personalitzat",
172169
"description": "Esteu segur que voleu suprimir aquest mode {{scope}}? Això també suprimirà la carpeta de regles associada a: {{rulesFolderPath}}",
173170
"descriptionNoRules": "Esteu segur que voleu suprimir aquest mode personalitzat?",
174-
"cancel": "Cancel·la",
175171
"confirm": "Suprimeix"
176172
}
177173
}

src/i18n/locales/de/common.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@
1919
"delete_config_profile": "Möchtest du dieses Konfigurationsprofil wirklich löschen?",
2020
"delete_custom_mode_with_rules": "Bist du sicher, dass du diesen {scope}-Modus löschen möchtest?\n\nDadurch wird auch der zugehörige Regelordner unter folgender Adresse gelöscht:\n{rulesFolderPath}",
2121
"delete_message": "Was möchtest du löschen?",
22-
"edit_message": "Alle Nachrichten nach dieser löschen?",
22+
"edit_warning": "Das Bearbeiten dieser Nachricht wird alle nachfolgenden Nachrichten in der Unterhaltung löschen. Möchtest du fortfahren?",
2323
"delete_just_this_message": "Nur diese Nachricht",
24-
"edit_just_this_message": "Nein, nur diese bearbeiten",
2524
"delete_this_and_subsequent": "Diese und alle nachfolgenden Nachrichten",
26-
"edit_this_and_delete_subsequent": "Ja"
25+
"proceed": "Fortfahren"
2726
},
2827
"errors": {
2928
"invalid_data_uri": "Ungültiges Daten-URI-Format",
@@ -107,13 +106,11 @@
107106
"answers": {
108107
"yes": "Ja",
109108
"no": "Nein",
110-
"cancel": "Abbrechen",
111109
"remove": "Entfernen",
112110
"keep": "Behalten"
113111
},
114112
"buttons": {
115113
"save": "Speichern",
116-
"cancel": "Abbrechen",
117114
"edit": "Bearbeiten"
118115
},
119116
"tasks": {
@@ -171,7 +168,6 @@
171168
"title": "Benutzerdefinierten Modus löschen",
172169
"description": "Bist du sicher, dass du diesen {{scope}}-Modus löschen möchtest? Dadurch wird auch der zugehörige Regelordner unter {{rulesFolderPath}} gelöscht",
173170
"descriptionNoRules": "Bist du sicher, dass du diesen benutzerdefinierten Modus löschen möchtest?",
174-
"cancel": "Abbrechen",
175171
"confirm": "Löschen"
176172
}
177173
}

0 commit comments

Comments
 (0)