UI for comments deletion by admins

This change depends on API implemented in Change 105052.

Feature: Issue 4644
Change-Id: I91137aaa69eef419e08c8a568cef9350d8a1448b
This commit is contained in:
Viktar Donich
2017-05-08 10:40:06 -07:00
parent c2399b9dbd
commit 9f047389f4
7 changed files with 232 additions and 1 deletions

View File

@@ -0,0 +1,69 @@
<!--
Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<link rel="import" href="../../../bower_components/iron-autogrow-textarea/iron-autogrow-textarea.html">
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../shared/gr-confirm-dialog/gr-confirm-dialog.html">
<dom-module id="gr-confirm-delete-comment-dialog">
<template>
<style>
:host {
display: block;
}
:host([disabled]) {
opacity: .5;
pointer-events: none;
}
.main {
display: flex;
flex-direction: column;
width: 100%;
}
label {
cursor: pointer;
display: block;
width: 100%;
}
iron-autogrow-textarea {
font-family: var(--monospace-font-family);
padding: 0;
width: 73ch; /* Add a char to account for the border. */
--iron-autogrow-textarea {
border: 1px solid #ddd;
font-family: var(--monospace-font-family);
}
}
</style>
<gr-confirm-dialog
confirm-label="Delete"
on-confirm="_handleConfirmTap"
on-cancel="_handleCancelTap">
<div class="header">Delete Comment</div>
<div class="main">
<label for="messageInput">Enter comment delete reason</label>
<iron-autogrow-textarea
id="messageInput"
class="message"
autocomplete="on"
placeholder="<Insert reasoning here>"
bind-value="{{message}}"></iron-autogrow-textarea>
</div>
</gr-confirm-dialog>
</template>
<script src="gr-confirm-delete-comment-dialog.js"></script>
</dom-module>

View File

@@ -0,0 +1,50 @@
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
(function() {
'use strict';
Polymer({
is: 'gr-confirm-delete-comment-dialog',
/**
* Fired when the confirm button is pressed.
*
* @event confirm
*/
/**
* Fired when the cancel button is pressed.
*
* @event cancel
*/
properties: {
message: String,
},
resetFocus: function() {
this.$.messageInput.textarea.focus();
},
_handleConfirmTap: function(e) {
e.preventDefault();
this.fire('confirm', {reason: this.message}, {bubbles: false});
},
_handleCancelTap: function(e) {
e.preventDefault();
this.fire('cancel', null, {bubbles: false});
},
});
})();

View File

@@ -19,10 +19,13 @@ limitations under the License.
<link rel="import" href="../../shared/gr-button/gr-button.html">
<link rel="import" href="../../shared/gr-date-formatter/gr-date-formatter.html">
<link rel="import" href="../../shared/gr-formatted-text/gr-formatted-text.html">
<link rel="import" href="../../shared/gr-storage/gr-storage.html">
<link rel="import" href="../../shared/gr-overlay/gr-overlay.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../../shared/gr-storage/gr-storage.html">
<link rel="import" href="../../shared/gr-tooltip-content/gr-tooltip-content.html">
<link rel="import" href="../gr-confirm-delete-comment-dialog/gr-confirm-delete-comment-dialog.html">
<script src="../../../scripts/rootElement.js"></script>
<dom-module id="gr-diff-comment">
<template>
@@ -72,6 +75,8 @@ limitations under the License.
.date {
justify-content: flex-end;
margin-left: 5px;
min-width: 4.5em;
text-align: right;
white-space: nowrap;
}
a.date:link,
@@ -177,6 +182,15 @@ limitations under the License.
color: #333;
font-size: 12px;
}
gr-confirm-dialog .main {
background-color: #fef;
display: flex;
flex-direction: column;
width: 100%;
}
#deleteBtn {
margin-top: .5em;
}
</style>
<div id="container"
class="container"
@@ -256,6 +270,13 @@ limitations under the License.
<div class="action unresolved hideOnPublished" hidden$="[[resolved]]">
Unresolved
</div>
<gr-button
id="deleteBtn"
class="action delete"
on-tap="_handleCommentDelete"
hidden$="[[!_isAdmin]]">
Delete
</gr-button>
</div>
<div class="actions robotActions" hidden$="[[!_showRobotActions]]">
<gr-button class="action fix"
@@ -265,6 +286,12 @@ limitations under the License.
</gr-button>
</div>
</div>
<gr-overlay id="overlay" with-backdrop>
<gr-confirm-delete-comment-dialog id="confirmDeleteComment"
on-confirm="_handleConfirmDeleteComment"
on-cancel="_handleCancelDeleteComment">
</gr-confirm-delete-comment-dialog>
</gr-overlay>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
<gr-storage id="storage"></gr-storage>
</template>

View File

@@ -90,6 +90,10 @@
},
projectConfig: Object,
robotButtonDisabled: Boolean,
_isAdmin: {
type: Boolean,
value: false,
},
_xhrPromise: Object, // Used for testing.
_messageText: {
@@ -118,6 +122,9 @@
} else if (this.comment) {
this.collapsed = this.comment.collapsed;
}
this._getIsAdmin().then(function(isAdmin) {
this._isAdmin = isAdmin;
}.bind(this));
},
detached: function() {
@@ -141,6 +148,10 @@
return this.side === 'PARENT';
},
_getIsAdmin: function() {
return this.$.restAPI.getIsAdmin();
},
save: function() {
this.comment.message = this._messageText;
@@ -462,5 +473,24 @@
this.comment.unresolved = !resolved;
this.fire('comment-update', this._getEventPayload());
},
_handleCommentDelete: function() {
Polymer.dom(Gerrit.getRootElement()).appendChild(this.$.overlay);
this.$.overlay.open();
},
_handleCancelDeleteComment: function() {
Polymer.dom(Gerrit.getRootElement()).removeChild(this.$.overlay);
this.$.overlay.close();
},
_handleConfirmDeleteComment: function() {
this.$.restAPI.deleteComment(
this.changeNum, this.patchNum, this.comment.id,
this.$.confirmDeleteComment.message).then(function(newComment) {
this._handleCancelDeleteComment();
this.comment = newComment;
}.bind(this));
},
});
})();

View File

@@ -248,6 +248,27 @@ limitations under the License.
assert.isTrue(element._handleSave.called);
});
});
test('delete comment button for non-admins is hidden', function() {
element._isAdmin = false;
assert.isTrue(element.$$('.action.delete').hidden);
});
test('delete comment', function(done) {
sandbox.stub(
element.$.restAPI, 'deleteComment').returns(Promise.resolve());
sandbox.spy(element.$.overlay, 'open');
element.changeNum = 42;
element.patchNum = 0xDEADBEEF;
element._isAdmin = true;
MockInteractions.tap(element.$$('.action.delete'));
element.$.overlay.open.lastCall.returnValue.then(function() {
element.$.confirmDeleteComment.message = 'removal reason';
element._handleConfirmDeleteComment();
assert.isTrue(element.$.restAPI.deleteComment.calledWith(
42, 0xDEADBEEF, 'baf0414d_60047215', 'removal reason'));
done();
});
});
});
suite('gr-diff-comment draft tests', function() {

View File

@@ -339,6 +339,18 @@
});
},
getIsAdmin() {
return this.getLoggedIn().then(isLoggedIn => {
if (isLoggedIn) {
return this.getAccountCapabilities();
} else {
return Promise.resolve();
}
}).then(capabilities => {
return capabilities && capabilities.administrateServer;
});
},
checkCredentials() {
// Skip the REST response cache.
return this.fetchJSON('/accounts/self/detail');
@@ -1113,5 +1125,14 @@
return this.send(
'POST', this.getChangeActionURL(changeNum, null, '/ready'), review);
},
deleteComment: function(changeNum, patchNum, commentID, reason) {
var url = this._changeBaseURL(changeNum, patchNum) +
'/comments/' + commentID + '/delete';
return this.send('POST', url, {reason: reason}).then(
function(response) {
return this.getResponseObject(response);
}.bind(this));
},
});
})();

View File

@@ -630,5 +630,18 @@ limitations under the License.
assert.isTrue(element.send.calledWith(
'POST', '/changes/42/ready', {message: 'Please review.'}));
});
test('deleteComment', done => {
sandbox.stub(element, 'send').returns(Promise.resolve());
sandbox.stub(element, 'getResponseObject').returns('some response');
element.deleteComment('foo', 'bar', '01234', 'removal reason')
.then(response => {
assert.equal(response, 'some response');
done();
});
assert.isTrue(element.send.calledWith(
'POST', '/changes/foo/revisions/bar/comments/01234/delete',
{reason:'removal reason'}));
});
});
</script>