Merge ~ilasc/launchpad:add-delete-comment-ui into launchpad:master

Proposed by Ioana Lasc
Status: Merged
Approved by: Ioana Lasc
Approved revision: 9e7b120d76e23d3341cf9953a95d3858f0c6bec3
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~ilasc/launchpad:add-delete-comment-ui
Merge into: launchpad:master
Diff against target: 268 lines (+148/-4)
6 files modified
lib/lp/answers/templates/questionmessage-display.pt (+4/-0)
lib/lp/bugs/templates/bugcomment-box.pt (+4/-1)
lib/lp/code/templates/codereviewcomment-header.pt (+4/-1)
lib/lp/services/messages/javascript/messages.edit.js (+79/-1)
lib/lp/services/messages/javascript/tests/test_messages.edit.html (+2/-0)
lib/lp/services/messages/javascript/tests/test_messages.edit.js (+55/-1)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+406012@code.launchpad.net

Commit message

Add delete comment UI

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

This basically all looks good as far as it goes, thanks! As discussed on Mattermost, though, I think we need to wire up some kind of confirmation here before landing this: it feels a little too easy to accidentally delete messages right now, either due to not having very good pointer coordination or by not understanding what the icon means.

review: Needs Fixing
Revision history for this message
Ioana Lasc (ilasc) :
82c1799... by Ioana Lasc

Shorten revision list heading

9e7b120... by Ioana Lasc

Add confirmation dialog to delete comment

Revision history for this message
Ioana Lasc (ilasc) wrote :

Added a dialog popup for confirmation prior to actual deletion, screenshots here:

https://chat.canonical.com/canonical/pl/8xh5eduda7839pd9juhubd9bze
https://chat.canonical.com/canonical/pl/643y4suakpgfmyn7d4o9pbjcrc

MP now ready for another look.

Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/lib/lp/answers/templates/questionmessage-display.pt b/lib/lp/answers/templates/questionmessage-display.pt
index 49973ab..fa39275 100644
--- a/lib/lp/answers/templates/questionmessage-display.pt
+++ b/lib/lp/answers/templates/questionmessage-display.pt
@@ -59,6 +59,10 @@
59 <img class="sprite edit action-icon editable-message-edit-btn"59 <img class="sprite edit action-icon editable-message-edit-btn"
60 tal:condition="view/can_edit"/>60 tal:condition="view/can_edit"/>
61 </td>61 </td>
62 <td>
63 <img class="sprite remove action-icon editable-message-delete-btn"
64 tal:condition="view/can_edit"/>
65 </td>
62 <td class="bug-comment-index">66 <td class="bug-comment-index">
63 <a67 <a
64 tal:content="string: #${context/display_index}" />68 tal:content="string: #${context/display_index}" />
diff --git a/lib/lp/bugs/templates/bugcomment-box.pt b/lib/lp/bugs/templates/bugcomment-box.pt
index 1e1882a..c9f1d60 100644
--- a/lib/lp/bugs/templates/bugcomment-box.pt
+++ b/lib/lp/bugs/templates/bugcomment-box.pt
@@ -92,7 +92,10 @@
92 <img class="sprite edit action-icon editable-message-edit-btn"92 <img class="sprite edit action-icon editable-message-edit-btn"
93 tal:condition="view/can_edit"/>93 tal:condition="view/can_edit"/>
94 </td>94 </td>
9595 <td>
96 <img class="sprite remove action-icon editable-message-delete-btn"
97 tal:condition="view/can_edit"/>
98 </td>
96 <td class="bug-comment-index">99 <td class="bug-comment-index">
97 <a itemprop="url"100 <a itemprop="url"
98 tal:attributes="href comment/fmt:url"101 tal:attributes="href comment/fmt:url"
diff --git a/lib/lp/code/templates/codereviewcomment-header.pt b/lib/lp/code/templates/codereviewcomment-header.pt
index 3511b9f..8ddea58 100644
--- a/lib/lp/code/templates/codereviewcomment-header.pt
+++ b/lib/lp/code/templates/codereviewcomment-header.pt
@@ -59,7 +59,10 @@
59 <img class="sprite edit action-icon editable-message-edit-btn"59 <img class="sprite edit action-icon editable-message-edit-btn"
60 tal:condition="view/can_edit"/>60 tal:condition="view/can_edit"/>
61 </td>61 </td>
6262 <td>
63 <img class="sprite remove action-icon editable-message-delete-btn"
64 tal:condition="view/can_edit"/>
65 </td>
63 <td class="bug-comment-index">66 <td class="bug-comment-index">
64 <a itemprop="url"67 <a itemprop="url"
65 tal:attributes="href context/fmt:url">#</a>68 tal:attributes="href context/fmt:url">#</a>
diff --git a/lib/lp/services/messages/javascript/messages.edit.js b/lib/lp/services/messages/javascript/messages.edit.js
index 56762e8..48c9b8a 100644
--- a/lib/lp/services/messages/javascript/messages.edit.js
+++ b/lib/lp/services/messages/javascript/messages.edit.js
@@ -39,6 +39,15 @@ YUI.add('lp.services.messages.edit', function(Y) {
39 "Please try again in a few minutes."39 "Please try again in a few minutes."
40 );40 );
4141
42 module.confirm_delete_message = (
43 "Are you sure you want to delete this "+
44 "comment and all its revisions?");
45
46 // Making it easier to mock on tests.
47 module.confirm = function(msg) {
48 return confirm(msg);
49 };
50
42 module.htmlify_msg = function(text) {51 module.htmlify_msg = function(text) {
43 text = text.replace(/&/g, "&amp;");52 text = text.replace(/&/g, "&amp;");
44 text = text.replace(/</g, "&lt;");53 text = text.replace(/</g, "&lt;");
@@ -70,6 +79,20 @@ YUI.add('lp.services.messages.edit', function(Y) {
70 this.lp_client.named_post(msg_url, 'editContent', config);79 this.lp_client.named_post(msg_url, 'editContent', config);
71 };80 };
7281
82 module.deleteMessageContent = function(
83 msg_path, on_success, on_failure) {
84 var msg_url = "/api/devel" + msg_path;
85 if (module.confirm(module.confirm_delete_message)) {
86 var config = {
87 on: {
88 success: on_success,
89 failure: on_failure
90 }
91 };
92 this.lp_client.named_post(msg_url, 'deleteContent', config);
93 }
94 };
95
73 module.showNotification = function(container, msg, can_dismiss) {96 module.showNotification = function(container, msg, can_dismiss) {
74 can_dismiss = can_dismiss || false;97 can_dismiss = can_dismiss || false;
75 // Clean up previous notification.98 // Clean up previous notification.
@@ -168,6 +191,41 @@ YUI.add('lp.services.messages.edit', function(Y) {
168 });191 });
169 };192 };
170193
194 // What to do when a message is deleted in the backend.
195 module.onMessageDeleted = function(elements, baseurl) {
196 elements.msg_body_text.getDOMNode().innerHTML = '';
197 // if after a delete the user wants to edit the empty
198 // message placeholder, they won't be able to
199 // unless we enable the text area and update button
200 elements.textarea.getDOMNode().disabled = false;
201 elements.update_btn.getDOMNode().disabled = false;
202 module.hideLoading(elements.container);
203 elements.last_edit.getDOMNode().innerHTML = (
204 ' <a href="#" class="editable-message-last-edit-link">' +
205 '(message and all revisions deleted a moment ago):' +
206 '</a>');
207
208 // Wire click handler to the newly created
209 // "message deleted / last edit" button.
210 var last_edit_btn = elements.container.one(
211 '.editable-message-last-edit-link');
212 last_edit_btn.on('click', function(e) {
213 e.preventDefault();
214 module.onLastEditClick(elements, baseurl);
215 });
216 };
217
218 // What to do when a message fails to delete on the backend.
219 module.onMessageDeleteError = function(elements, err) {
220 // When something goes wrong at the backend, re-enable
221 // UI elements and display an error.
222 module.showNotification(
223 elements.container,
224 module.msg_edit_error_notification, true);
225 elements.textarea.getDOMNode().disabled = false;
226 elements.update_btn.getDOMNode().disabled = false;
227 };
228
171 // What to do when a message fails to update on the backend.229 // What to do when a message fails to update on the backend.
172 module.onMessageSaveError = function(elements, err) {230 module.onMessageSaveError = function(elements, err) {
173 // When something goes wrong at the backend, re-enable231 // When something goes wrong at the backend, re-enable
@@ -179,6 +237,21 @@ YUI.add('lp.services.messages.edit', function(Y) {
179 elements.update_btn.getDOMNode().disabled = false;237 elements.update_btn.getDOMNode().disabled = false;
180 };238 };
181239
240 // What to do when a user clicks the delete button on a msg.
241 module.onDeleteClick = function(elements, baseurl) {
242 module.showLoading(elements.container);
243 var textarea = elements.textarea.getDOMNode();
244 textarea.disabled = true;
245 elements.delete_btn.getDOMNode().disabled = true;
246
247 module.deleteMessageContent(
248 baseurl,
249 function(err) {
250 module.onMessageDeleted(elements, baseurl);
251 },
252 function(err) { module.onMessageDeleteError(elements, err); }
253 );
254 };
182 module.fillMessageRevisions = function(elements, revisions) {255 module.fillMessageRevisions = function(elements, revisions) {
183 // Position the message revision list element.256 // Position the message revision list element.
184 revisions = revisions.reverse();257 revisions = revisions.reverse();
@@ -255,7 +328,8 @@ YUI.add('lp.services.messages.edit', function(Y) {
255 "update_btn": container.one('.editable-message-update-btn'),328 "update_btn": container.one('.editable-message-update-btn'),
256 "cancel_btn": container.one('.editable-message-cancel-btn'),329 "cancel_btn": container.one('.editable-message-cancel-btn'),
257 "last_edit": container.one('.editable-message-last-edit-date'),330 "last_edit": container.one('.editable-message-last-edit-date'),
258 "last_edit_btn": container.one('.editable-message-last-edit-link')331 "last_edit_btn": container.one('.editable-message-last-edit-link'),
332 "delete_btn": container.one('.editable-message-delete-btn')
259 };333 };
260 // If the msg body or the msg form are not defined, don't try to do334 // If the msg body or the msg form are not defined, don't try to do
261 // anything else.335 // anything else.
@@ -290,6 +364,10 @@ YUI.add('lp.services.messages.edit', function(Y) {
290 elements.cancel_btn.on('click', function(e) {364 elements.cancel_btn.on('click', function(e) {
291 module.onEditCancelClick(elements);365 module.onEditCancelClick(elements);
292 });366 });
367
368 elements.delete_btn.on('click', function(e) {
369 module.onDeleteClick(elements, baseurl);
370 });
293 };371 };
294372
295 module.setup = function() {373 module.setup = function() {
diff --git a/lib/lp/services/messages/javascript/tests/test_messages.edit.html b/lib/lp/services/messages/javascript/tests/test_messages.edit.html
index 9d394c2..ce4d0df 100644
--- a/lib/lp/services/messages/javascript/tests/test_messages.edit.html
+++ b/lib/lp/services/messages/javascript/tests/test_messages.edit.html
@@ -98,6 +98,7 @@ GNU Affero General Public License version 3 (see the file LICENSE).
98 The message is above :)98 The message is above :)
99 </div>99 </div>
100 <img class="sprite edit action-icon editable-message-edit-btn" />100 <img class="sprite edit action-icon editable-message-edit-btn" />
101 <img class="sprite remove action-icon editable-message-delete-btn" />
101102
102 <div class="editable-message-form">103 <div class="editable-message-form">
103 <textarea></textarea>104 <textarea></textarea>
@@ -141,6 +142,7 @@ GNU Affero General Public License version 3 (see the file LICENSE).
141 The message is above :)142 The message is above :)
142 </div>143 </div>
143 <img class="sprite edit action-icon editable-message-edit-btn" />144 <img class="sprite edit action-icon editable-message-edit-btn" />
145 <img class="sprite remove action-icon editable-message-delete-btn" />
144146
145 <div class="editable-message-form">147 <div class="editable-message-form">
146 <textarea></textarea>148 <textarea></textarea>
diff --git a/lib/lp/services/messages/javascript/tests/test_messages.edit.js b/lib/lp/services/messages/javascript/tests/test_messages.edit.js
index d9644f0..0bcccb3 100644
--- a/lib/lp/services/messages/javascript/tests/test_messages.edit.js
+++ b/lib/lp/services/messages/javascript/tests/test_messages.edit.js
@@ -71,6 +71,10 @@ YUI.add('lp.services.messages.edit.test', function(Y) {
71 this.containers[0].one(".editable-message-update-btn"),71 this.containers[0].one(".editable-message-update-btn"),
72 this.containers[1].one(".editable-message-update-btn")72 this.containers[1].one(".editable-message-update-btn")
73 ];73 ];
74 this.delete_btns = [
75 this.containers[0].one(".editable-message-delete-btn"),
76 this.containers[1].one(".editable-message-delete-btn")
77 ];
7478
75 for(var i=0 ; i<this.containers.length ; i++) {79 for(var i=0 ; i<this.containers.length ; i++) {
76 this.msg_texts[i].getDOMNode().innerHTML = (80 this.msg_texts[i].getDOMNode().innerHTML = (
@@ -235,8 +239,58 @@ YUI.add('lp.services.messages.edit.test', function(Y) {
235 revisions_container.one(239 revisions_container.one(
236 '.message-revision-close').simulate('click');240 '.message-revision-close').simulate('click');
237 Y.Assert.areSame('none', revisions_container.getStyle('display'));241 Y.Assert.areSame('none', revisions_container.getStyle('display'));
238 }242 },
243
244 test_delete_comment: function() {
245 module.setup();
246 module.lp_client.io_provider = new Y.lp.testing.mockio.MockIo();
247 module.confirm = function(){
248 return 'True';
249 };
250 // Delete the comment
251 this.delete_btns[1].simulate('click');
252 module.lp_client.io_provider.success({
253 responseText:'null',
254 responseHeaders: {'Content-Type': 'application/json'}
255 });
256
257 // Check message was deleted
258 Y.Assert.areSame(
259 "",
260 this.msg_texts[1].getDOMNode().innerHTML);
261
262 // All forms should be released.
263 Y.Assert.isFalse(this.textareas[1].getDOMNode().disabled);
264 Y.Assert.isFalse(this.update_btns[1].getDOMNode().disabled);
265 Y.Assert.isFalse(this.textareas[0].getDOMNode().disabled);
266 Y.Assert.isFalse(this.update_btns[0].getDOMNode().disabled);
267
268 // Check forms and msg bodies visibility are back to normal.
269 assertDisplayStyle(this.msg_bodies[0], 'block');
270 assertDisplayStyle(this.msg_forms[0], 'none');
271 assertDisplayStyle(this.msg_bodies[1], 'block');
272 assertDisplayStyle(this.msg_forms[1], 'none');
239273
274 // Check that the request was made correctly.
275 var last_request = module.lp_client.io_provider.last_request;
276 Y.Assert.areSame("/api/devel/message/2", last_request.url);
277 Y.Assert.areSame("POST", last_request.config.method);
278 Y.Assert.areSame(
279 "ws.op=deleteContent",
280 last_request.config.data);
281
282 // Check that the "last edit" header changed.
283 Y.Assert.areSame(":", this.last_edit[0].getDOMNode().innerHTML);
284 Y.Assert.areSame(
285 ' <a href="#" class="editable-message-last-edit-link">' +
286 '(message and all revisions deleted a moment ago):</a>',
287 this.last_edit[1].getDOMNode().innerHTML);
288
289 // Check the pop-up revisions list is empty after deleting
290 var revisions = this.revision_history_lists[1].all(
291 ".message-revision-item");
292 Y.Assert.areSame(0, revisions.size());
293 }
240 };294 };
241295
242 suite.add(new Y.Test.Case(TestMessageEdit));296 suite.add(new Y.Test.Case(TestMessageEdit));

Subscribers

People subscribed via source and target branches

to status/vote changes: