
Observing both revisions and _sortedRevisions in <gr-patch-range-select> is unnecessary. This change does not fix any bugs, but does simplify the code. Change-Id: I01e5562e3ca40ba5f0be1d73036bbeb70313c7cf
247 lines
8.5 KiB
JavaScript
247 lines
8.5 KiB
JavaScript
// Copyright (C) 2016 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';
|
|
|
|
// Maximum length for patch set descriptions.
|
|
const PATCH_DESC_MAX_LENGTH = 500;
|
|
|
|
/**
|
|
* Fired when the patch range changes
|
|
*
|
|
* @event patch-range-change
|
|
*
|
|
* @property {string} patchNum
|
|
* @property {string} basePatchNum
|
|
*/
|
|
|
|
Polymer({
|
|
is: 'gr-patch-range-select',
|
|
|
|
properties: {
|
|
availablePatches: Array,
|
|
_baseDropdownContent: {
|
|
type: Object,
|
|
computed: '_computeBaseDropdownContent(availablePatches, patchNum,' +
|
|
'_sortedRevisions, comments)',
|
|
},
|
|
_patchDropdownContent: {
|
|
type: Object,
|
|
computed: '_computePatchDropdownContent(availablePatches,' +
|
|
'basePatchNum, _sortedRevisions, comments)',
|
|
},
|
|
changeNum: String,
|
|
// In the case of a patch range select (like diff view) comments should
|
|
// be an empty array, so that the patch and base content computed values
|
|
// get triggered.
|
|
comments: {
|
|
type: Object,
|
|
value: () => { return {}; },
|
|
},
|
|
/** @type {{ meta_a: !Array, meta_b: !Array}} */
|
|
filesWeblinks: Object,
|
|
patchNum: String,
|
|
basePatchNum: String,
|
|
revisions: Object,
|
|
_sortedRevisions: Array,
|
|
},
|
|
|
|
observers: [
|
|
'_updateSortedRevisions(revisions.*)',
|
|
],
|
|
|
|
behaviors: [Gerrit.PatchSetBehavior],
|
|
|
|
_computeBaseDropdownContent(availablePatches, patchNum, _sortedRevisions,
|
|
comments) {
|
|
const dropdownContent = [];
|
|
for (const basePatch of availablePatches) {
|
|
const basePatchNum = basePatch.num;
|
|
dropdownContent.push({
|
|
disabled: this._computeLeftDisabled(
|
|
basePatch.num, patchNum, _sortedRevisions),
|
|
triggerText: `Patchset ${basePatchNum}`,
|
|
text: `Patchset ${basePatchNum}` +
|
|
this._computePatchSetCommentsString(this.comments, basePatchNum),
|
|
mobileText: this._computeMobileText(basePatchNum, comments,
|
|
_sortedRevisions),
|
|
bottomText: `${this._computePatchSetDescription(
|
|
_sortedRevisions, basePatchNum)}`,
|
|
value: basePatch.num,
|
|
});
|
|
}
|
|
dropdownContent.push({
|
|
text: 'Base',
|
|
value: 'PARENT',
|
|
});
|
|
return dropdownContent;
|
|
},
|
|
|
|
_computeMobileText(patchNum, comments, revisions) {
|
|
return `${patchNum}` +
|
|
`${this._computePatchSetCommentsString(this.comments, patchNum)}` +
|
|
`${this._computePatchSetDescription(revisions, patchNum, true)}`;
|
|
},
|
|
|
|
_computePatchDropdownContent(availablePatches, basePatchNum,
|
|
_sortedRevisions, comments) {
|
|
const dropdownContent = [];
|
|
for (const patch of availablePatches) {
|
|
const patchNum = patch.num;
|
|
dropdownContent.push({
|
|
disabled: this._computeRightDisabled(basePatchNum, patchNum,
|
|
_sortedRevisions),
|
|
triggerText: `${patchNum === 'edit' ? '': 'Patchset '}` +
|
|
patchNum,
|
|
text: `${patchNum === 'edit' ? '': 'Patchset '}${patchNum}` +
|
|
`${this._computePatchSetCommentsString(
|
|
this.comments, patchNum)}`,
|
|
mobileText: this._computeMobileText(patchNum, comments,
|
|
_sortedRevisions),
|
|
bottomText: `${this._computePatchSetDescription(
|
|
_sortedRevisions, patchNum)}`,
|
|
value: patchNum,
|
|
});
|
|
}
|
|
return dropdownContent;
|
|
},
|
|
|
|
_updateSortedRevisions(revisionsRecord) {
|
|
const revisions = revisionsRecord.base;
|
|
this._sortedRevisions = this.sortRevisions(Object.values(revisions));
|
|
},
|
|
|
|
/**
|
|
* The basePatchNum should always be <= patchNum -- because sortedRevisions
|
|
* is sorted in reverse order (higher patchset nums first), invalid base
|
|
* patch nums have an index greater than the index of patchNum.
|
|
* @param {number|string} basePatchNum The possible base patch num.
|
|
* @param {number|string} patchNum The current selected patch num.
|
|
* @param {!Array} sortedRevisions
|
|
*/
|
|
_computeLeftDisabled(basePatchNum, patchNum, sortedRevisions) {
|
|
return this.findSortedIndex(basePatchNum, sortedRevisions) <=
|
|
this.findSortedIndex(patchNum, sortedRevisions);
|
|
},
|
|
|
|
/**
|
|
* The basePatchNum should always be <= patchNum -- because sortedRevisions
|
|
* is sorted in reverse order (higher patchset nums first), invalid patch
|
|
* nums have an index greater than the index of basePatchNum.
|
|
* In addition, if the current basePatchNum is 'PARENT', all patchNums are
|
|
* valid.
|
|
* @param {number|string} basePatchNum The current selected base patch num.
|
|
* @param {number|string} patchNum The possible patch num.
|
|
* @param {!Array} sortedRevisions
|
|
*/
|
|
_computeRightDisabled(basePatchNum, patchNum, sortedRevisions) {
|
|
if (basePatchNum === 'PARENT') { return false; }
|
|
return this.findSortedIndex(basePatchNum, sortedRevisions) <=
|
|
this.findSortedIndex(patchNum, sortedRevisions);
|
|
},
|
|
|
|
// Copied from gr-file-list
|
|
// @todo(beckysiegel) clean up.
|
|
_getCommentsForPath(comments, patchNum, path) {
|
|
return (comments[path] || []).filter(c => {
|
|
return this.patchNumEquals(c.patch_set, patchNum);
|
|
});
|
|
},
|
|
|
|
// Copied from gr-file-list
|
|
// @todo(beckysiegel) clean up.
|
|
_computeUnresolvedNum(comments, drafts, patchNum, path) {
|
|
comments = this._getCommentsForPath(comments, patchNum, path);
|
|
drafts = this._getCommentsForPath(drafts, patchNum, path);
|
|
comments = comments.concat(drafts);
|
|
|
|
// Create an object where every comment ID is the key of an unresolved
|
|
// comment.
|
|
|
|
const idMap = comments.reduce((acc, comment) => {
|
|
if (comment.unresolved) {
|
|
acc[comment.id] = true;
|
|
}
|
|
return acc;
|
|
}, {});
|
|
|
|
// Set false for the comments that are marked as parents.
|
|
for (const comment of comments) {
|
|
idMap[comment.in_reply_to] = false;
|
|
}
|
|
|
|
// The unresolved comments are the comments that still have true.
|
|
const unresolvedLeaves = Object.keys(idMap).filter(key => {
|
|
return idMap[key];
|
|
});
|
|
|
|
return unresolvedLeaves.length;
|
|
},
|
|
|
|
_computePatchSetCommentsString(allComments, patchNum) {
|
|
// todo (beckysiegel) get comment strings for diff view also.
|
|
if (!allComments) { return ''; }
|
|
let numComments = 0;
|
|
let numUnresolved = 0;
|
|
for (const file in allComments) {
|
|
if (allComments.hasOwnProperty(file)) {
|
|
numComments += this._getCommentsForPath(
|
|
allComments, patchNum, file).length;
|
|
numUnresolved += this._computeUnresolvedNum(
|
|
allComments, {}, patchNum, file);
|
|
}
|
|
}
|
|
let commentsStr = '';
|
|
if (numComments > 0) {
|
|
commentsStr = ' (' + numComments + ' comments';
|
|
if (numUnresolved > 0) {
|
|
commentsStr += ', ' + numUnresolved + ' unresolved';
|
|
}
|
|
commentsStr += ')';
|
|
}
|
|
return commentsStr;
|
|
},
|
|
|
|
/**
|
|
* @param {!Array} revisions
|
|
* @param {number|string} patchNum
|
|
* @param {boolean=} opt_addFrontSpace
|
|
*/
|
|
_computePatchSetDescription(revisions, patchNum, opt_addFrontSpace) {
|
|
const rev = this.getRevisionByPatchNum(revisions, patchNum);
|
|
return (rev && rev.description) ?
|
|
(opt_addFrontSpace ? ' ' : '') +
|
|
rev.description.substring(0, PATCH_DESC_MAX_LENGTH) : '';
|
|
},
|
|
|
|
/**
|
|
* Catches value-change events from the patchset dropdowns and determines
|
|
* whether or not a patch change event should be fired.
|
|
*/
|
|
_handlePatchChange(e) {
|
|
const detail = {patchNum: this.patchNum, basePatchNum: this.basePatchNum};
|
|
const target = Polymer.dom(e).localTarget;
|
|
|
|
if (target === this.$.patchNumDropdown) {
|
|
detail.patchNum = e.detail.value;
|
|
} else {
|
|
detail.basePatchNum = e.detail.value;
|
|
}
|
|
|
|
this.dispatchEvent(
|
|
new CustomEvent('patch-range-change', {detail, bubbles: false}));
|
|
},
|
|
});
|
|
})();
|