Update gr-comment-api to get comments grouped by thread

Change-Id: Id6f1ca24b17137ea89a7f6ba24f62179f0aecb30
This commit is contained in:
Becky Siegel 2018-01-30 16:23:14 -08:00
parent b6c39d621f
commit 21ad8d38c7
2 changed files with 289 additions and 15 deletions
polygerrit-ui/app/elements/diff/gr-comment-api

@ -118,10 +118,26 @@
* @return {!Object}
*/
ChangeComments.prototype.getAllPublishedComments = function(opt_patchNum) {
return this.getAllComments(false, opt_patchNum);
};
/**
* Gets all the comments and robot comments for the given change.
*
* @param {boolean=} opt_includeDrafts
* @param {number=} opt_patchNum
* @return {!Object}
*/
ChangeComments.prototype.getAllComments = function(opt_includeDrafts,
opt_patchNum) {
const paths = this.getPaths();
const publishedComments = {};
for (const path of Object.keys(paths)) {
publishedComments[path] = this.getAllCommentsForPath(path, opt_patchNum);
let commentsToAdd = this.getAllCommentsForPath(path, opt_patchNum);
if (opt_includeDrafts) {
commentsToAdd = commentsToAdd.concat(this.getAllDraftsForPath(path));
}
publishedComments[path] = commentsToAdd;
}
return publishedComments;
};
@ -214,6 +230,25 @@
};
};
/**
* @param {!Object} comments Object keyed by file, with a value of an array
* of comments left on that file.
* @return {!Array} A flattened list of all comments, where each comment
* also includes the file that it was left on, which was the key of the
* originall object.
*/
ChangeComments.prototype._commentObjToArrayWithFile = function(comments) {
let commentArr = [];
for (const file of Object.keys(comments)) {
const commentsForFile = [];
for (const comment of comments[file]) {
commentsForFile.push(Object.assign({__path: file}, comment));
}
commentArr = commentArr.concat(commentsForFile);
}
return commentArr;
};
ChangeComments.prototype._commentObjToArray = function(comments) {
let commentArr = [];
for (const file of Object.keys(comments)) {
@ -295,6 +330,49 @@
return unresolvedLeaves.length;
};
ChangeComments.prototype.getAllThreadsForChange = function() {
const comments = this._commentObjToArrayWithFile(this.getAllComments(true));
return this.getCommentThreads(comments);
};
/**
* Computes all of the comments in thread format.
*
* @param {!Array} comments
* @return {!Array}
*/
ChangeComments.prototype.getCommentThreads = function(comments) {
const threads = comments.reduce((groups, comment) => {
const path = comment.__path;
const patchset = comment.patch_set;
const line = comment.line;
const range = comment.range;
const side = comment.side;
let key = `${path}-${patchset}-${line}`;
if (range) {
key = `${key}-${range.start_line}-${range.start_character}-` +
`${range.end_line}-${range.end_character}`;
}
if (side) {
key = `${key}-${side}`;
}
const groupObj = {
comments: [],
patchNum: patchset,
path,
line,
};
if (comment.side) {
groupObj.commentSide = side;
}
groups[key] = groups[key] || groupObj;
groups[key].comments.push(comment);
return groups;
}, {});
return Object.values(threads);
};
/**
* Whether the given comment should be included in the base side of the
* given patch range.
@ -386,7 +464,6 @@
});
},
/**
* Re-initialize _changeComments with a new ChangeComments object, that
* uses the previous values for comments and robot comments, but fetches

@ -229,32 +229,37 @@ limitations under the License.
setup(() => {
element._changeComments._drafts = {
'file/one': [
{id: 11, patch_set: 2, side: PARENT},
{id: 12, patch_set: 2},
{id: 11, patch_set: 2, side: PARENT, line: 1},
{id: 12, patch_set: 2, line: 1},
],
};
element._changeComments._robotComments = {
'file/one': [
{id: 1, patch_set: 2, side: PARENT},
{id: 2, patch_set: 2, unresolved: true},
{id: 1, patch_set: 2, side: PARENT, line: 1, range: {
start_line: 1,
start_character: 2,
end_line: 2,
end_character: 2,
}},
{id: 2, patch_set: 2, unresolved: true, line: 1},
],
};
element._changeComments._comments = {
'file/one': [
{id: 3, patch_set: 2, side: PARENT},
{id: 4, patch_set: 2},
{id: 3, patch_set: 2, side: PARENT, line: 2},
{id: 4, patch_set: 2, line: 1},
],
'file/two': [
{id: 5, patch_set: 2},
{id: 6, patch_set: 3},
{id: 5, patch_set: 2, line: 2},
{id: 6, patch_set: 3, line: 2},
],
'file/three': [
{id: 7, patch_set: 2, side: PARENT, unresolved: true},
{id: 8, patch_set: 3},
{id: 7, patch_set: 2, side: PARENT, unresolved: true, line: 1},
{id: 8, patch_set: 3, line: 1},
],
'file/four': [
{id: 9, patch_set: 5, side: PARENT},
{i: 10, patch_set: 5},
{id: 9, patch_set: 5, side: PARENT, line: 1},
{i: 10, patch_set: 5, line: 1},
],
};
});
@ -358,10 +363,202 @@ limitations under the License.
});
test('getAllPublishedComments', () => {
const publishedComments = element._changeComments
let publishedComments = element._changeComments
.getAllPublishedComments();
assert.equal(Object.keys(publishedComments).length, 4);
assert.equal(Object.keys(publishedComments[['file/one']]).length, 4);
assert.equal(Object.keys(publishedComments[['file/two']]).length, 2);
publishedComments = element._changeComments
.getAllPublishedComments(2);
assert.equal(Object.keys(publishedComments[['file/one']]).length, 4);
assert.equal(Object.keys(publishedComments[['file/two']]).length, 1);
});
test('getAllComments', () => {
let comments = element._changeComments.getAllComments();
assert.equal(Object.keys(comments).length, 4);
assert.equal(Object.keys(comments[['file/one']]).length, 4);
assert.equal(Object.keys(comments[['file/two']]).length, 2);
comments = element._changeComments.getAllComments(false, 2);
assert.equal(Object.keys(comments).length, 4);
assert.equal(Object.keys(comments[['file/one']]).length, 4);
assert.equal(Object.keys(comments[['file/two']]).length, 1);
// Include drafts
comments = element._changeComments.getAllComments(true);
assert.equal(Object.keys(comments).length, 4);
assert.equal(Object.keys(comments[['file/one']]).length, 6);
assert.equal(Object.keys(comments[['file/two']]).length, 2);
comments = element._changeComments.getAllComments(true, 2);
assert.equal(Object.keys(comments).length, 4);
assert.equal(Object.keys(comments[['file/one']]).length, 6);
assert.equal(Object.keys(comments[['file/two']]).length, 1);
});
test('computeAllThreads', () => {
const expectedThreads = [
{
comments: [
{
id: 3,
patch_set: 2,
side: 'PARENT',
line: 2,
__path: 'file/one',
},
],
commentSide: 'PARENT',
patchNum: 2,
path: 'file/one',
line: 2,
},
{
comments: [
{
id: 4,
patch_set: 2,
line: 1,
__path: 'file/one',
},
{
id: 2,
patch_set: 2,
unresolved: true,
line: 1,
__path: 'file/one',
},
{
id: 12,
patch_set: 2,
line: 1,
__path: 'file/one',
},
],
patchNum: 2,
path: 'file/one',
line: 1,
},
{
comments: [
{
id: 1,
patch_set: 2,
side: 'PARENT',
line: 1,
range: {
start_line: 1,
start_character: 2,
end_line: 2,
end_character: 2,
},
__path: 'file/one',
},
],
commentSide: 'PARENT',
patchNum: 2,
path: 'file/one',
line: 1,
},
{
comments: [
{
id: 11,
patch_set: 2,
side: 'PARENT',
line: 1,
__path: 'file/one',
},
],
commentSide: 'PARENT',
patchNum: 2,
path: 'file/one',
line: 1,
},
{
comments: [
{
id: 5,
patch_set: 2,
line: 2,
__path: 'file/two',
},
],
patchNum: 2,
path: 'file/two',
line: 2,
},
{
comments: [
{
id: 6,
patch_set: 3,
line: 2,
__path: 'file/two',
},
],
patchNum: 3,
path: 'file/two',
line: 2,
},
{
comments: [
{
id: 7,
patch_set: 2,
side: 'PARENT',
unresolved: true,
line: 1,
__path: 'file/three',
},
],
commentSide: 'PARENT',
patchNum: 2,
path: 'file/three',
line: 1,
},
{
comments: [
{
id: 8,
patch_set: 3,
line: 1,
__path: 'file/three',
},
],
patchNum: 3,
path: 'file/three',
line: 1,
},
{
comments: [
{
id: 9,
patch_set: 5,
side: 'PARENT',
line: 1,
__path: 'file/four',
},
],
commentSide: 'PARENT',
patchNum: 5,
path: 'file/four',
line: 1,
},
{
comments: [
{
i: 10,
patch_set: 5,
line: 1,
__path: 'file/four',
},
],
patchNum: 5,
path: 'file/four',
line: 1,
},
];
const threads = element._changeComments.getAllThreadsForChange();
assert.deepEqual(threads, expectedThreads);
});
});
});