| /** |
| * @license |
| * 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', |
| _legacyUndefinedCheck: true, |
| |
| properties: { |
| availablePatches: Array, |
| _baseDropdownContent: { |
| type: Object, |
| computed: '_computeBaseDropdownContent(availablePatches, patchNum,' + |
| '_sortedRevisions, changeComments, revisionInfo)', |
| }, |
| _patchDropdownContent: { |
| type: Object, |
| computed: '_computePatchDropdownContent(availablePatches,' + |
| 'basePatchNum, _sortedRevisions, changeComments)', |
| }, |
| changeNum: String, |
| changeComments: Object, |
| /** @type {{ meta_a: !Array, meta_b: !Array}} */ |
| filesWeblinks: Object, |
| patchNum: String, |
| basePatchNum: String, |
| revisions: Object, |
| revisionInfo: Object, |
| _sortedRevisions: Array, |
| }, |
| |
| observers: [ |
| '_updateSortedRevisions(revisions.*)', |
| ], |
| |
| behaviors: [Gerrit.PatchSetBehavior], |
| |
| _computeBaseDropdownContent(availablePatches, patchNum, _sortedRevisions, |
| changeComments, revisionInfo) { |
| // Polymer 2: check for undefined |
| if ([ |
| availablePatches, |
| patchNum, |
| _sortedRevisions, |
| changeComments, |
| revisionInfo, |
| ].some(arg => arg === undefined)) { |
| return undefined; |
| } |
| |
| const parentCounts = revisionInfo.getParentCountMap(); |
| const currentParentCount = parentCounts.hasOwnProperty(patchNum) ? |
| parentCounts[patchNum] : 1; |
| const maxParents = revisionInfo.getMaxParents(); |
| const isMerge = currentParentCount > 1; |
| |
| const dropdownContent = []; |
| for (const basePatch of availablePatches) { |
| const basePatchNum = basePatch.num; |
| const entry = this._createDropdownEntry(basePatchNum, 'Patchset ', |
| _sortedRevisions, changeComments); |
| dropdownContent.push(Object.assign({}, entry, { |
| disabled: this._computeLeftDisabled( |
| basePatch.num, patchNum, _sortedRevisions), |
| })); |
| } |
| |
| dropdownContent.push({ |
| text: isMerge ? 'Auto Merge' : 'Base', |
| value: 'PARENT', |
| }); |
| |
| for (let idx = 0; isMerge && idx < maxParents; idx++) { |
| dropdownContent.push({ |
| disabled: idx >= currentParentCount, |
| triggerText: `Parent ${idx + 1}`, |
| text: `Parent ${idx + 1}`, |
| mobileText: `Parent ${idx + 1}`, |
| value: -(idx + 1), |
| }); |
| } |
| |
| return dropdownContent; |
| }, |
| |
| _computeMobileText(patchNum, changeComments, revisions) { |
| return `${patchNum}` + |
| `${this._computePatchSetCommentsString(changeComments, patchNum)}` + |
| `${this._computePatchSetDescription(revisions, patchNum, true)}`; |
| }, |
| |
| _computePatchDropdownContent(availablePatches, basePatchNum, |
| _sortedRevisions, changeComments) { |
| // Polymer 2: check for undefined |
| if ([ |
| availablePatches, |
| basePatchNum, |
| _sortedRevisions, |
| changeComments, |
| ].some(arg => arg === undefined)) { |
| return undefined; |
| } |
| |
| const dropdownContent = []; |
| for (const patch of availablePatches) { |
| const patchNum = patch.num; |
| const entry = this._createDropdownEntry( |
| patchNum, patchNum === 'edit' ? '' : 'Patchset ', _sortedRevisions, |
| changeComments); |
| dropdownContent.push(Object.assign({}, entry, { |
| disabled: this._computeRightDisabled(basePatchNum, patchNum, |
| _sortedRevisions), |
| })); |
| } |
| return dropdownContent; |
| }, |
| |
| _createDropdownEntry(patchNum, prefix, sortedRevisions, changeComments) { |
| const entry = { |
| triggerText: `${prefix}${patchNum}`, |
| text: `${prefix}${patchNum}` + |
| `${this._computePatchSetCommentsString( |
| changeComments, patchNum)}`, |
| mobileText: this._computeMobileText(patchNum, changeComments, |
| sortedRevisions), |
| bottomText: `${this._computePatchSetDescription( |
| sortedRevisions, patchNum)}`, |
| value: patchNum, |
| }; |
| const date = this._computePatchSetDate(sortedRevisions, patchNum); |
| if (date) { |
| entry['date'] = date; |
| } |
| return entry; |
| }, |
| |
| _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. |
| * |
| * If the curent basePatchNum is a parent index, then only patches that have |
| * at least that many parents are valid. |
| * |
| * @param {number|string} basePatchNum The current selected base patch num. |
| * @param {number|string} patchNum The possible patch num. |
| * @param {!Array} sortedRevisions |
| * @return {boolean} |
| */ |
| _computeRightDisabled(basePatchNum, patchNum, sortedRevisions) { |
| if (this.patchNumEquals(basePatchNum, 'PARENT')) { return false; } |
| |
| if (this.isMergeParent(basePatchNum)) { |
| // Note: parent indices use 1-offset. |
| return this.revisionInfo.getParentCount(patchNum) < |
| this.getParentIndex(basePatchNum); |
| } |
| |
| return this.findSortedIndex(basePatchNum, sortedRevisions) <= |
| this.findSortedIndex(patchNum, sortedRevisions); |
| }, |
| |
| |
| _computePatchSetCommentsString(changeComments, patchNum) { |
| if (!changeComments) { return; } |
| |
| const commentCount = changeComments.computeCommentCount(patchNum); |
| const commentString = GrCountStringFormatter.computePluralString( |
| commentCount, 'comment'); |
| |
| const unresolvedCount = changeComments.computeUnresolvedNum(patchNum); |
| const unresolvedString = GrCountStringFormatter.computeString( |
| unresolvedCount, 'unresolved'); |
| |
| if (!commentString.length && !unresolvedString.length) { |
| return ''; |
| } |
| |
| return ` (${commentString}` + |
| // Add a comma + space if both comments and unresolved |
| (commentString && unresolvedString ? ', ' : '') + |
| `${unresolvedString})`; |
| }, |
| |
| /** |
| * @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) : ''; |
| }, |
| |
| /** |
| * @param {!Array} revisions |
| * @param {number|string} patchNum |
| */ |
| _computePatchSetDate(revisions, patchNum) { |
| const rev = this.getRevisionByPatchNum(revisions, patchNum); |
| return rev ? rev.created : undefined; |
| }, |
| |
| /** |
| * 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})); |
| }, |
| }); |
| })(); |