Add comments/drafts to gr-new-diff

Change-Id: I8110b521ab83a31be5db7e3d65268186485db04d
This commit is contained in:
Andrew Bonventre
2016-03-20 14:14:20 -04:00
parent 00f0839714
commit 02f71327cf
12 changed files with 306 additions and 30 deletions

View File

@@ -15,6 +15,7 @@ limitations under the License.
--> -->
<link rel="import" href="../../../bower_components/polymer/polymer.html"> <link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../gr-diff-comment/gr-diff-comment.html"> <link rel="import" href="../gr-diff-comment/gr-diff-comment.html">
<dom-module id="gr-diff-comment-thread"> <dom-module id="gr-diff-comment-thread">
@@ -41,7 +42,7 @@ limitations under the License.
change-num="[[changeNum]]" change-num="[[changeNum]]"
patch-num="[[patchNum]]" patch-num="[[patchNum]]"
draft="[[comment.__draft]]" draft="[[comment.__draft]]"
show-actions="[[showActions]]" show-actions="[[_showActions]]"
project-config="[[projectConfig]]" project-config="[[projectConfig]]"
on-height-change="_handleCommentHeightChange" on-height-change="_handleCommentHeightChange"
on-reply="_handleCommentReply" on-reply="_handleCommentReply"
@@ -49,6 +50,7 @@ limitations under the License.
on-done="_handleCommentDone"></gr-diff-comment> on-done="_handleCommentDone"></gr-diff-comment>
</template> </template>
</div> </div>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template> </template>
<script src="gr-diff-comment-thread.js"></script> <script src="gr-diff-comment-thread.js"></script>
</dom-module> </dom-module>

View File

@@ -37,9 +37,9 @@
}, },
patchNum: String, patchNum: String,
path: String, path: String,
showActions: Boolean,
projectConfig: Object, projectConfig: Object,
_showActions: Boolean,
_boundWindowResizeHandler: { _boundWindowResizeHandler: {
type: Function, type: Function,
value: function() { return this._handleWindowResize.bind(this); } value: function() { return this._handleWindowResize.bind(this); }
@@ -57,6 +57,10 @@
], ],
attached: function() { attached: function() {
this._getLoggedIn().then(function(loggedIn) {
this._showActions = loggedIn;
}.bind(this));
window.addEventListener('resize', this._boundWindowResizeHandler); window.addEventListener('resize', this._boundWindowResizeHandler);
}, },
@@ -64,6 +68,10 @@
window.removeEventListener('resize', this._boundWindowResizeHandler); window.removeEventListener('resize', this._boundWindowResizeHandler);
}, },
_getLoggedIn: function() {
return this.$.restAPI.getLoggedIn();
},
_handleWindowResize: function(e) { _handleWindowResize: function(e) {
this._heightChanged(); this._heightChanged();
}, },

View File

@@ -41,6 +41,9 @@ limitations under the License.
suite('gr-diff-comment-thread tests', function() { suite('gr-diff-comment-thread tests', function() {
var element; var element;
setup(function() { setup(function() {
stub('gr-rest-api-interface', {
getLoggedIn: function() { return Promise.resolve(false); },
});
element = fixture('basic'); element = fixture('basic');
}); });
@@ -124,6 +127,9 @@ limitations under the License.
var server; var server;
setup(function() { setup(function() {
stub('gr-rest-api-interface', {
getLoggedIn: function() { return Promise.resolve(false); },
});
element = fixture('withComment'); element = fixture('withComment');
element.comments = [{ element.comments = [{
author: { author: {

View File

@@ -33,7 +33,6 @@
prefs: { prefs: {
type: Object, type: Object,
notify: true, notify: true,
value: function() { return {}; },
}, },
disabled: { disabled: {
type: Boolean, type: Boolean,

View File

@@ -411,7 +411,6 @@
threadEl.patchNum = thread.patchNum || this.patchNum; threadEl.patchNum = thread.patchNum || this.patchNum;
threadEl.path = this.path; threadEl.path = this.path;
threadEl.comments = thread.comments; threadEl.comments = thread.comments;
threadEl.showActions = this.canComment;
threadEl.projectConfig = this.projectConfig; threadEl.projectConfig = this.projectConfig;
this.$.numbers.insertBefore(lineEl, beforeLineEl); this.$.numbers.insertBefore(lineEl, beforeLineEl);

View File

@@ -14,8 +14,8 @@
(function(window, GrDiffBuilder) { (function(window, GrDiffBuilder) {
'use strict'; 'use strict';
function GrDiffBuilderSideBySide(diff, prefs, outputEl) { function GrDiffBuilderSideBySide(diff, comments, prefs, outputEl) {
GrDiffBuilder.call(this, diff, prefs, outputEl); GrDiffBuilder.call(this, diff, comments, prefs, outputEl);
} }
GrDiffBuilderSideBySide.prototype = Object.create(GrDiffBuilder.prototype); GrDiffBuilderSideBySide.prototype = Object.create(GrDiffBuilder.prototype);
GrDiffBuilderSideBySide.prototype.constructor = GrDiffBuilderSideBySide; GrDiffBuilderSideBySide.prototype.constructor = GrDiffBuilderSideBySide;
@@ -35,23 +35,28 @@
GrDiffBuilderSideBySide.prototype._createRow = function(section, leftLine, GrDiffBuilderSideBySide.prototype._createRow = function(section, leftLine,
rightLine) { rightLine) {
var row = this._createElement('tr'); var row = this._createElement('tr');
this._createPair(section, row, leftLine, leftLine.beforeNumber, 'left'); this._appendPair(section, row, leftLine, leftLine.beforeNumber,
this._createPair(section, row, rightLine, rightLine.afterNumber, 'right'); GrDiffBuilder.Side.LEFT);
this._appendPair(section, row, rightLine, rightLine.afterNumber,
GrDiffBuilder.Side.RIGHT);
return row; return row;
}; };
GrDiffBuilderSideBySide.prototype._createPair = function(section, row, line, GrDiffBuilderSideBySide.prototype._appendPair = function(section, row, line,
lineNumber, side) { lineNumber, side) {
row.appendChild(this._createLineEl(line, lineNumber, line.type)); row.appendChild(this._createLineEl(line, lineNumber, line.type));
var action = this._createContextControl(section, line); var action = this._createContextControl(section, line);
if (action) { if (action) {
row.appendChild(action); row.appendChild(action);
} else { } else {
var el = this._createTextEl(line); var textEl = this._createTextEl(line);
el.classList.add(side); textEl.classList.add(side);
row.appendChild(el); var threadEl = this._createCommentThread(line, side);
if (threadEl) {
textEl.appendChild(threadEl);
}
row.appendChild(textEl);
} }
return row;
}; };
window.GrDiffBuilderSideBySide = GrDiffBuilderSideBySide; window.GrDiffBuilderSideBySide = GrDiffBuilderSideBySide;

View File

@@ -14,8 +14,8 @@
(function(window, GrDiffBuilder) { (function(window, GrDiffBuilder) {
'use strict'; 'use strict';
function GrDiffBuilderUnified(diff, prefs, outputEl) { function GrDiffBuilderUnified(diff, comments, prefs, outputEl) {
GrDiffBuilder.call(this, diff, prefs, outputEl); GrDiffBuilder.call(this, diff, comments, prefs, outputEl);
} }
GrDiffBuilderUnified.prototype = Object.create(GrDiffBuilder.prototype); GrDiffBuilderUnified.prototype = Object.create(GrDiffBuilder.prototype);
GrDiffBuilderUnified.prototype.constructor = GrDiffBuilderUnified; GrDiffBuilderUnified.prototype.constructor = GrDiffBuilderUnified;
@@ -41,7 +41,12 @@
if (action) { if (action) {
row.appendChild(action); row.appendChild(action);
} else { } else {
row.appendChild(this._createTextEl(line)); var textEl = this._createTextEl(line);
var threadEl = this._createCommentThread(line);
if (threadEl) {
textEl.appendChild(threadEl);
}
row.appendChild(textEl);
} }
return row; return row;
}; };

View File

@@ -14,7 +14,8 @@
(function(window, GrDiffGroup, GrDiffLine) { (function(window, GrDiffGroup, GrDiffLine) {
'use strict'; 'use strict';
function GrDiffBuilder(diff, prefs, outputEl) { function GrDiffBuilder(diff, comments, prefs, outputEl) {
this._comments = comments;
this._prefs = prefs; this._prefs = prefs;
this._outputEl = outputEl; this._outputEl = outputEl;
this._groups = []; this._groups = [];
@@ -38,6 +39,11 @@
REMOVED: 'a', REMOVED: 'a',
}; };
GrDiffBuilder.Side = {
LEFT: 'left',
RIGHT: 'right',
};
GrDiffBuilder.prototype.emitDiff = function() { GrDiffBuilder.prototype.emitDiff = function() {
for (var i = 0; i < this._groups.length; i++) { for (var i = 0; i < this._groups.length; i++) {
this.emitGroup(this._groups[i]); this.emitGroup(this._groups[i]);
@@ -167,6 +173,40 @@
return td; return td;
}; };
GrDiffBuilder.prototype._getCommentsForLine = function(comments, line,
opt_side) {
var leftComments = comments[GrDiffBuilder.Side.LEFT].filter(
function(c) { return c.line === line.beforeNumber; });
var rightComments = comments[GrDiffBuilder.Side.RIGHT].filter(
function(c) { return c.line === line.afterNumber; });
var result;
switch (opt_side) {
case GrDiffBuilder.Side.LEFT:
result = leftComments;
break;
case GrDiffBuilder.Side.RIGHT:
result = rightComments;
break;
default:
result = leftComments.concat(rightComments);
break;
}
return result;
};
GrDiffBuilder.prototype._createCommentThread = function(line, opt_side) {
var comments = this._getCommentsForLine(this._comments, line, opt_side);
if (!comments || comments.length === 0) {
return null;
}
var threadEl = document.createElement('gr-diff-comment-thread');
threadEl.comments = comments;
return threadEl;
};
GrDiffBuilder.prototype._createLineEl = function(line, number, type) { GrDiffBuilder.prototype._createLineEl = function(line, number, type) {
var td = this._createElement('td', 'lineNum'); var td = this._createElement('td', 'lineNum');
if (line.type === GrDiffLine.Type.BLANK) { if (line.type === GrDiffLine.Type.BLANK) {

View File

@@ -207,7 +207,8 @@ limitations under the License.
line_length: 10, line_length: 10,
tab_size: 4, tab_size: 4,
}; };
var builder = new GrDiffBuilder({content: []}, prefs); var builder =
new GrDiffBuilder({content: []}, {left: [], right: []}, prefs);
var text = 'abcdef'; var text = 'abcdef';
assert.equal(builder._addNewlines(text, text), text); assert.equal(builder._addNewlines(text, text), text);
@@ -240,7 +241,8 @@ limitations under the License.
show_tabs: true, show_tabs: true,
tab_size: 4, tab_size: 4,
}; };
var builder = new GrDiffBuilder({content: []}, prefs); var builder =
new GrDiffBuilder({content: []}, {left: [], right: []}, prefs);
var html = 'abc\tdef'; var html = 'abc\tdef';
var wrapper = builder._getTabWrapper(prefs.tab_size, prefs.show_tabs); var wrapper = builder._getTabWrapper(prefs.tab_size, prefs.show_tabs);
@@ -252,5 +254,45 @@ limitations under the License.
'"><img src="/" onerror="alert(1);"><span class="', '"><img src="/" onerror="alert(1);"><span class="',
true)); true));
}); });
test('comments', function() {
var line = new GrDiffLine(GrDiffLine.Type.BOTH);
line.beforeNumber = 3;
line.afterNumber = 5;
var comments = {left: [], right:[]};
assert.deepEqual(
GrDiffBuilder.prototype._getCommentsForLine(comments, line), []);
assert.deepEqual(
GrDiffBuilder.prototype._getCommentsForLine(comments, line,
GrDiffBuilder.Side.LEFT),
[]);
assert.deepEqual(
GrDiffBuilder.prototype._getCommentsForLine(comments, line,
GrDiffBuilder.Side.RIGHT),
[]);
comments = {
left: [
{id: 'l3', line: 3},
{id: 'l5', line: 5},
],
right: [
{id: 'r3', line: 3},
{id: 'r5', line: 5},
],
};
assert.deepEqual(
GrDiffBuilder.prototype._getCommentsForLine(comments, line),
[{id: 'l3', line: 3}, {id: 'r5', line: 5}]);
assert.deepEqual(
GrDiffBuilder.prototype._getCommentsForLine(comments, line,
GrDiffBuilder.Side.LEFT),
[{id: 'l3', line: 3}]);
assert.deepEqual(
GrDiffBuilder.prototype._getCommentsForLine(comments, line,
GrDiffBuilder.Side.RIGHT),
[{id: 'r5', line: 5}]);
});
}); });
</script> </script>

View File

@@ -20,6 +20,7 @@ limitations under the License.
<link rel="import" href="../../shared/gr-request/gr-request.html"> <link rel="import" href="../../shared/gr-request/gr-request.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html"> <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../gr-diff-comment-thread/gr-diff-comment-thread.html">
<link rel="import" href="../gr-diff-preferences/gr-diff-preferences.html"> <link rel="import" href="../gr-diff-preferences/gr-diff-preferences.html">
<link rel="import" href="../gr-patch-range-select/gr-patch-range-select.html"> <link rel="import" href="../gr-patch-range-select/gr-patch-range-select.html">
@@ -70,6 +71,13 @@ limitations under the License.
.lineNum:before { .lineNum:before {
content: attr(data-value); content: attr(data-value);
} }
.canComment .lineNum[data-value] {
cursor: pointer;
text-decoration: underline;
}
.canComment .lineNum[data-value]:hover {
background-color: #ccc;
}
.content { .content {
overflow: hidden; overflow: hidden;
width: var(--content-width, 80ch); width: var(--content-width, 80ch);
@@ -138,7 +146,7 @@ limitations under the License.
on-cancel="_handlePrefsCancel"></gr-diff-preferences> on-cancel="_handlePrefsCancel"></gr-diff-preferences>
</gr-overlay> </gr-overlay>
<div class="diffContainer" <div class$="[[_computeContainerClass(_loggedIn)]]"
on-tap="_handleTap" on-tap="_handleTap"
on-mousedown="_handleMouseDown" on-mousedown="_handleMouseDown"
on-copy="_handleCopy"> on-copy="_handleCopy">

View File

@@ -38,6 +38,10 @@
}, },
projectConfig: Object, projectConfig: Object,
_loggedIn: {
type: Boolean,
value: false,
},
_loading: { _loading: {
type: Boolean, type: Boolean,
value: true, value: true,
@@ -52,20 +56,43 @@
type: String, type: String,
observer: '_selectionSideChanged', observer: '_selectionSideChanged',
}, },
_comments: Object,
}, },
observers: [ observers: [
'_render(_diff, prefs.*)', '_render(_diff, _comments, prefs.*)',
], ],
attached: function() {
this._getLoggedIn().then(function(loggedIn) {
this._loggedIn = loggedIn;
}.bind(this));
},
reload: function() { reload: function() {
this.$.diffTable.innerHTML = null; this.$.diffTable.innerHTML = null;
this._loading = true; this._loading = true;
return this._getDiff().then(function(diff) { var promises = [];
promises.push(this._getDiff().then(function(diff) {
this._diff = diff; this._diff = diff;
this._loading = false; this._loading = false;
}.bind(this)); }.bind(this)));
promises.push(this._getDiffCommentsAndDrafts().then(function(comments) {
this._comments = comments;
}.bind(this)));
return Promise.all(promises);
},
_computeContainerClass: function(loggedIn) {
var classes = ['diffContainer'];
if (loggedIn) {
classes.push('canComment');
}
return classes.join(' ');
}, },
_handleTap: function(e) { _handleTap: function(e) {
@@ -135,12 +162,11 @@
sectionEl.parentNode.removeChild(sectionEl); sectionEl.parentNode.removeChild(sectionEl);
}, },
_render: function(diff, prefsChangeRecord) { _render: function(diff, comments, prefsChangeRecord) {
var prefs = prefsChangeRecord.base; var prefs = prefsChangeRecord.base;
this.customStyle['--content-width'] = prefs.line_length + 'ch'; this.customStyle['--content-width'] = prefs.line_length + 'ch';
this.updateStyles(); this.updateStyles();
this._builder = this._getDiffBuilder(diff, comments, prefs);
this._builder = this._getDiffBuilder(diff, prefs);
this._builder.emitDiff(diff.content); this._builder.emitDiff(diff.content);
}, },
@@ -152,11 +178,63 @@
this.path); this.path);
}, },
_getDiffBuilder: function(diff, prefs) { _getDiffComments: function() {
return this.$.restAPI.getDiffComments(
this.changeNum,
this.patchRange.basePatchNum,
this.patchRange.patchNum,
this.path);
},
_getDiffDrafts: function() {
return this._getLoggedIn().then(function(loggedIn) {
if (!loggedIn) {
return Promise.resolve({baseComments: [], comments: []});
}
return this.$.restAPI.getDiffDrafts(
this.changeNum,
this.patchRange.basePatchNum,
this.patchRange.patchNum,
this.path);
}.bind(this));
},
_getDiffCommentsAndDrafts: function() {
var promises = [];
promises.push(this._getDiffComments());
promises.push(this._getDiffDrafts());
return Promise.all(promises).then(function(results) {
return Promise.resolve({
comments: results[0],
drafts: results[1],
});
}).then(this._normalizeDiffCommentsAndDrafts);
},
_normalizeDiffCommentsAndDrafts: function(results) {
function markAsDraft(d) {
d.__draft = true;
return d;
}
var baseDrafts = results.drafts.baseComments.map(markAsDraft);
var drafts = results.drafts.comments.map(markAsDraft);
return Promise.resolve({
left: results.comments.baseComments.concat(baseDrafts),
right: results.comments.comments.concat(drafts),
});
},
_getLoggedIn: function() {
return this.$.restAPI.getLoggedIn();
},
_getDiffBuilder: function(diff, comments, prefs) {
if (this._viewMode === DiffViewMode.SIDE_BY_SIDE) { if (this._viewMode === DiffViewMode.SIDE_BY_SIDE) {
return new GrDiffBuilderSideBySide(diff, prefs, this.$.diffTable); return new GrDiffBuilderSideBySide(diff, comments, prefs,
this.$.diffTable);
} else if (this._viewMode === DiffViewMode.UNIFIED) { } else if (this._viewMode === DiffViewMode.UNIFIED) {
return new GrDiffBuilderUnified(diff, prefs, this.$.diffTable); return new GrDiffBuilderUnified(diff, comments, prefs,
this.$.diffTable);
} }
throw Error('Unsupported diff view mode: ' + this._viewMode); throw Error('Unsupported diff view mode: ' + this._viewMode);
}, },

View File

@@ -35,14 +35,98 @@ limitations under the License.
var element; var element;
setup(function() { setup(function() {
stub('gr-rest-api-interface', {
getLoggedIn: function() { return Promise.resolve(false); },
})
element = fixture('basic'); element = fixture('basic');
}); });
teardown(function() { teardown(function() {
}); });
test('basic', function() { test('get drafts logged out', function(done) {
element.patchRange = {basePatchNum: 0, patchNum: 0};
var getDraftsStub = sinon.stub(element.$.restAPI, 'getDiffDrafts');
var loggedInStub = sinon.stub(element, '_getLoggedIn',
function() { return Promise.resolve(false); });
element._getDiffDrafts().then(function(result) {
assert.deepEqual(result, {baseComments: [], comments: []});
sinon.assert.notCalled(getDraftsStub);
loggedInStub.restore();
getDraftsStub.restore();
done();
});
});
test('get drafts logged in', function(done) {
element.patchRange = {basePatchNum: 0, patchNum: 0};
var draftsResponse = {
baseComments: [{id: 'foo'}],
comments: [{id: 'bar'}],
};
var getDraftsStub = sinon.stub(element.$.restAPI, 'getDiffDrafts',
function() { return Promise.resolve(draftsResponse); });
var loggedInStub = sinon.stub(element, '_getLoggedIn',
function() { return Promise.resolve(true); });
element._getDiffDrafts().then(function(result) {
assert.deepEqual(result, draftsResponse);
loggedInStub.restore();
getDraftsStub.restore();
done();
});
});
test('get comments and drafts', function(done) {
var loggedInStub = sinon.stub(element, '_getLoggedIn',
function() { return Promise.resolve(true); });
var comments = {
baseComments: [
{id: 'bc1'},
{id: 'bc2'},
],
comments: [
{id: 'c1'},
{id: 'c2'},
],
};
var diffCommentsStub = sinon.stub(element, '_getDiffComments',
function() { return Promise.resolve(comments); });
var drafts = {
baseComments: [
{id: 'bd1'},
{id: 'bd2'},
],
comments: [
{id: 'd1'},
{id: 'd2'},
],
};
var diffDraftsStub = sinon.stub(element, '_getDiffDrafts',
function() { return Promise.resolve(drafts); });
element._getDiffCommentsAndDrafts().then(function(result) {
assert.deepEqual(result, {
left: [
{id: 'bc1'},
{id: 'bc2'},
{id: 'bd1', __draft: true},
{id: 'bd2', __draft: true},
],
right: [
{id: 'c1'},
{id: 'c2'},
{id: 'd1', __draft: true},
{id: 'd2', __draft: true},
],
});
diffCommentsStub.restore();
diffDraftsStub.restore();
loggedInStub.restore();
done();
});
}); });
}); });
</script> </script>