| // 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'; |
| |
| // Maximum length for patch set descriptions. |
| const PATCH_DESC_MAX_LENGTH = 500; |
| |
| Polymer({ |
| is: 'gr-file-list-header', |
| |
| properties: { |
| account: Object, |
| allPatchSets: Array, |
| change: Object, |
| changeNum: String, |
| changeUrl: String, |
| comments: Object, |
| commitInfo: Object, |
| editLoaded: Boolean, |
| loggedIn: Boolean, |
| serverConfig: Object, |
| shownFileCount: Number, |
| diffPrefs: Object, |
| diffViewMode: String, |
| /** @type {?} */ |
| patchRange: { |
| type: Object, |
| observer: 'updateSelected', |
| }, |
| revisions: Array, |
| // Caps the number of files that can be shown and have the 'show diffs' / |
| // 'hide diffs' buttons still be functional. |
| _maxFilesForBulkActions: { |
| type: Number, |
| readOnly: true, |
| value: 225, |
| }, |
| _descriptionReadOnly: { |
| type: Boolean, |
| computed: '_computeDescriptionReadOnly(loggedIn, change, account)', |
| }, |
| _selectedPatchSet: String, |
| _diffAgainst: String, |
| }, |
| |
| behaviors: [ |
| Gerrit.PatchSetBehavior, |
| ], |
| |
| _expandAllDiffs() { |
| this.fire('expand-diffs'); |
| }, |
| |
| _collapseAllDiffs() { |
| this.fire('collapse-diffs'); |
| }, |
| |
| updateSelected() { |
| this._selectedPatchSet = this.patchRange.patchNum; |
| this._diffAgainst = this.patchRange.basePatchNum; |
| }, |
| |
| _computeDescriptionPlaceholder(readOnly) { |
| return (readOnly ? 'No' : 'Add a') + ' patch set description'; |
| }, |
| |
| _computeDescriptionReadOnly(loggedIn, change, account) { |
| return !(loggedIn && (account._account_id === change.owner._account_id)); |
| }, |
| |
| _computePatchSetDescription(change, patchNum) { |
| const rev = this.getRevisionByPatchNum(change.revisions, patchNum); |
| return (rev && rev.description) ? |
| rev.description.substring(0, PATCH_DESC_MAX_LENGTH) : ''; |
| }, |
| |
| |
| /** |
| * @param {!Object} revisions The revisions object keyed by revision hashes |
| * @param {?Object} patchSet A revision already fetched from {revisions} |
| * @return {string|undefined} the SHA hash corresponding to the revision. |
| */ |
| _getPatchsetHash(revisions, patchSet) { |
| for (const rev in revisions) { |
| if (revisions.hasOwnProperty(rev) && |
| revisions[rev] === patchSet) { |
| return rev; |
| } |
| } |
| }, |
| |
| _handleDescriptionChanged(e) { |
| const desc = e.detail.trim(); |
| const rev = this.getRevisionByPatchNum(this.change.revisions, |
| this._selectedPatchSet); |
| const sha = this._getPatchsetHash(this.change.revisions, rev); |
| this.$.restAPI.setDescription(this.changeNum, |
| this._selectedPatchSet, desc) |
| .then(res => { |
| if (res.ok) { |
| this.set(['_change', 'revisions', sha, 'description'], desc); |
| } |
| }); |
| }, |
| |
| _computeBasePatchDisabled(patchNum, currentPatchNum) { |
| return this.findSortedIndex(patchNum, this.revisions) >= |
| this.findSortedIndex(currentPatchNum, this.revisions); |
| }, |
| |
| _computePrefsButtonHidden(prefs, loggedIn) { |
| return !loggedIn || !prefs; |
| }, |
| |
| // Copied from gr-file-list |
| _getCommentsForPath(comments, patchNum, path) { |
| return (comments[path] || []).filter(c => { |
| return this.patchNumEquals(c.patch_set, patchNum); |
| }); |
| }, |
| |
| // Copied from gr-file-list |
| _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) { |
| 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; |
| }, |
| |
| _fileListActionsVisible(shownFileCount, maxFilesForBulkActions) { |
| return shownFileCount <= maxFilesForBulkActions; |
| }, |
| |
| /** |
| * Determines if a patch number should be disabled based on value of the |
| * basePatchNum from gr-file-list. |
| * @param {number} patchNum Patch number available in dropdown |
| * @param {number|string} basePatchNum Base patch number from file list |
| * @return {boolean} |
| */ |
| _computePatchSetDisabled(patchNum, basePatchNum) { |
| if (basePatchNum === 'PARENT') { return false; } |
| |
| return this.findSortedIndex(patchNum, this.revisions) <= |
| this.findSortedIndex(basePatchNum, this.revisions); |
| }, |
| |
| /** |
| * Change active patch to the provided patch num. |
| * @param {number|string} basePatchNum the base patch to be viewed. |
| * @param {number|string} patchNum the patch number to be viewed. |
| * @param {boolean} opt_forceParams When set to true, the resulting URL will |
| * always include the patch range, even if the requested patchNum is |
| * known to be the latest. |
| */ |
| _changePatchNum(patchNum, basePatchNum, opt_forceParams) { |
| if (!opt_forceParams) { |
| let currentPatchNum; |
| if (this.change.current_revision) { |
| currentPatchNum = |
| this.change.revisions[this.change.current_revision]._number; |
| } else { |
| currentPatchNum = this.computeLatestPatchNum(this.allPatchSets); |
| } |
| if (this.patchNumEquals(patchNum, currentPatchNum) && |
| basePatchNum === 'PARENT') { |
| Gerrit.Nav.navigateToChange(this.change); |
| return; |
| } |
| } |
| Gerrit.Nav.navigateToChange(this.change, patchNum, |
| basePatchNum); |
| }, |
| |
| _handleBasePatchChange(e) { |
| this._changePatchNum(this._selectedPatchSet, e.target.value, true); |
| }, |
| |
| _handlePatchChange(e) { |
| this._changePatchNum(e.target.value, this._diffAgainst, true); |
| }, |
| |
| _handlePrefsTap(e) { |
| e.preventDefault(); |
| this.fire('open-diff-prefs'); |
| }, |
| |
| _handleDownloadTap(e) { |
| e.preventDefault(); |
| this.fire('open-download-dialog'); |
| }, |
| |
| _computeEditLoadedClass(editLoaded) { |
| return editLoaded ? 'editLoaded' : ''; |
| }, |
| |
| _computePatchInfoClass(patchNum, allPatchSets) { |
| if (this.patchNumEquals(patchNum, this.EDIT_NAME)) { |
| return 'patchInfoEdit'; |
| } |
| |
| const latestNum = this.computeLatestPatchNum(allPatchSets); |
| if (this.patchNumEquals(patchNum, latestNum)) { |
| return ''; |
| } |
| return 'patchInfoOldPatchSet'; |
| }, |
| }); |
| })(); |