Files
gerrit/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.js
David Pursehouse ec26f04606 Merge branch 'stable-2.15' into stable-2.16
* stable-2.15:
  Consume JGit artifacts from Maven Central
  Consume JGit artifacts from Maven Central
  gr-related-changes: Don't show "Same topic" for only one change
  RelatedChanges: Don't show "Same Topic" for only one change
  ChangeEditApi: Allow to set options on change edit detail request
  Add Javadoc to clarify behavior of {Accounts|Changes|Groups}#withOptions
  OnlineNoteDbMigrationIT: improve readability of some tests
  Update git submodules
  Add release notes for Gerrit v2.10.8
  Add release notes for Gerrit v2.9.5
  Set version to 2.13.12
  Set version to 2.12.9
  Set version to 2.11.12
  Set version to 2.10.8
  Set version to 2.9.5

Change-Id: Id02a8afc6e4e8d42b759ed2ea28a0926411ff2e8
2019-01-18 21:47:17 +09:00

360 lines
10 KiB
JavaScript

/**
* @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';
Polymer({
is: 'gr-related-changes-list',
/**
* Fired when a new section is loaded so that the change view can determine
* a show more button is needed, sometimes before all the sections finish
* loading.
*
* @event new-section-loaded
*/
properties: {
change: Object,
hasParent: {
type: Boolean,
notify: true,
value: false,
},
patchNum: String,
parentChange: Object,
hidden: {
type: Boolean,
value: false,
reflectToAttribute: true,
},
loading: {
type: Boolean,
notify: true,
},
mergeable: Boolean,
_connectedRevisions: {
type: Array,
computed: '_computeConnectedRevisions(change, patchNum, ' +
'_relatedResponse.changes)',
},
/** @type {?} */
_relatedResponse: {
type: Object,
value() { return {changes: []}; },
},
/** @type {?} */
_submittedTogether: {
type: Object,
value() { return {changes: []}; },
},
_conflicts: {
type: Array,
value() { return []; },
},
_cherryPicks: {
type: Array,
value() { return []; },
},
_sameTopic: {
type: Array,
value() { return []; },
},
},
behaviors: [
Gerrit.PatchSetBehavior,
Gerrit.RESTClientBehavior,
],
observers: [
'_resultsChanged(_relatedResponse, _submittedTogether, ' +
'_conflicts, _cherryPicks, _sameTopic)',
],
clear() {
this.loading = true;
this.hidden = true;
this._relatedResponse = {changes: []};
this._submittedTogether = {changes: []};
this._conflicts = [];
this._cherryPicks = [];
this._sameTopic = [];
},
reload() {
if (!this.change || !this.patchNum) {
return Promise.resolve();
}
this.loading = true;
const promises = [
this._getRelatedChanges().then(response => {
this._relatedResponse = response;
this._fireReloadEvent();
this.hasParent = this._calculateHasParent(this.change.change_id,
response.changes);
}),
this._getSubmittedTogether().then(response => {
this._submittedTogether = response;
this._fireReloadEvent();
}),
this._getCherryPicks().then(response => {
this._cherryPicks = response;
this._fireReloadEvent();
}),
];
// Get conflicts if change is open and is mergeable.
if (this.changeIsOpen(this.change.status) && this.mergeable) {
promises.push(this._getConflicts().then(response => {
// Because the server doesn't always return a response and the
// template expects an array, always return an array.
this._conflicts = response ? response : [];
this._fireReloadEvent();
}));
}
promises.push(this._getServerConfig().then(config => {
if (this.change.topic && !config.change.submit_whole_topic) {
return this._getChangesWithSameTopic().then(response => {
this._sameTopic = response;
});
} else {
this._sameTopic = [];
}
return this._sameTopic;
}));
return Promise.all(promises).then(() => {
this.loading = false;
});
},
_fireReloadEvent() {
// The listener on the change computes height of the related changes
// section, so they have to be rendered first, and inside a dom-repeat,
// that requires a flush.
Polymer.dom.flush();
this.dispatchEvent(new CustomEvent('new-section-loaded'));
},
/**
* Determines whether or not the given change has a parent change. If there
* is a relation chain, and the change id is not the last item of the
* relation chain, there is a parent.
* @param {number} currentChangeId
* @param {!Array} relatedChanges
* @return {boolean}
*/
_calculateHasParent(currentChangeId, relatedChanges) {
return relatedChanges.length > 0 &&
relatedChanges[relatedChanges.length - 1].change_id !==
currentChangeId;
},
_getRelatedChanges() {
return this.$.restAPI.getRelatedChanges(this.change._number,
this.patchNum);
},
_getSubmittedTogether() {
return this.$.restAPI.getChangesSubmittedTogether(this.change._number);
},
_getServerConfig() {
return this.$.restAPI.getConfig();
},
_getConflicts() {
return this.$.restAPI.getChangeConflicts(this.change._number);
},
_getCherryPicks() {
return this.$.restAPI.getChangeCherryPicks(this.change.project,
this.change.change_id, this.change._number);
},
_getChangesWithSameTopic() {
return this.$.restAPI.getChangesWithSameTopic(this.change.topic,
this.change._number);
},
/**
* @param {number} changeNum
* @param {string} project
* @param {number=} opt_patchNum
* @return {string}
*/
_computeChangeURL(changeNum, project, opt_patchNum) {
return Gerrit.Nav.getUrlForChangeById(changeNum, project, opt_patchNum);
},
_computeChangeContainerClass(currentChange, relatedChange) {
const classes = ['changeContainer'];
if (this._changesEqual(relatedChange, currentChange)) {
classes.push('thisChange');
}
return classes.join(' ');
},
/**
* Do the given objects describe the same change? Compares the changes by
* their numbers.
* @see /Documentation/rest-api-changes.html#change-info
* @see /Documentation/rest-api-changes.html#related-change-and-commit-info
* @param {!Object} a Either ChangeInfo or RelatedChangeAndCommitInfo
* @param {!Object} b Either ChangeInfo or RelatedChangeAndCommitInfo
* @return {boolean}
*/
_changesEqual(a, b) {
const aNum = this._getChangeNumber(a);
const bNum = this._getChangeNumber(b);
return aNum === bNum;
},
/**
* Get the change number from either a ChangeInfo (such as those included in
* SubmittedTogetherInfo responses) or get the change number from a
* RelatedChangeAndCommitInfo (such as those included in a
* RelatedChangesInfo response).
* @see /Documentation/rest-api-changes.html#change-info
* @see /Documentation/rest-api-changes.html#related-change-and-commit-info
*
* @param {!Object} change Either a ChangeInfo or a
* RelatedChangeAndCommitInfo object.
* @return {number}
*/
_getChangeNumber(change) {
if (change.hasOwnProperty('_change_number')) {
return change._change_number;
}
return change._number;
},
_computeLinkClass(change) {
const statuses = [];
if (change.status == this.ChangeStatus.ABANDONED) {
statuses.push('strikethrough');
}
if (change.submittable) {
statuses.push('submittable');
}
return statuses.join(' ');
},
_computeChangeStatusClass(change) {
const classes = ['status'];
if (change._revision_number != change._current_revision_number) {
classes.push('notCurrent');
} else if (this._isIndirectAncestor(change)) {
classes.push('indirectAncestor');
} else if (change.submittable) {
classes.push('submittable');
} else if (change.status == this.ChangeStatus.NEW) {
classes.push('hidden');
}
return classes.join(' ');
},
_computeChangeStatus(change) {
switch (change.status) {
case this.ChangeStatus.MERGED:
return 'Merged';
case this.ChangeStatus.ABANDONED:
return 'Abandoned';
}
if (change._revision_number != change._current_revision_number) {
return 'Not current';
} else if (this._isIndirectAncestor(change)) {
return 'Indirect ancestor';
} else if (change.submittable) {
return 'Submittable';
}
return '';
},
_resultsChanged(related, submittedTogether, conflicts,
cherryPicks, sameTopic) {
const results = [
related && related.changes,
submittedTogether && submittedTogether.changes,
conflicts,
cherryPicks,
sameTopic,
];
for (let i = 0; i < results.length; i++) {
if (results[i] && results[i].length > 0) {
this.hidden = false;
this.fire('update', null, {bubbles: false});
return;
}
}
this.hidden = true;
},
_isIndirectAncestor(change) {
return !this._connectedRevisions.includes(change.commit.commit);
},
_computeConnectedRevisions(change, patchNum, relatedChanges) {
const connected = [];
let changeRevision;
for (const rev in change.revisions) {
if (this.patchNumEquals(change.revisions[rev]._number, patchNum)) {
changeRevision = rev;
}
}
const commits = relatedChanges.map(c => { return c.commit; });
let pos = commits.length - 1;
while (pos >= 0) {
const commit = commits[pos].commit;
connected.push(commit);
if (commit == changeRevision) {
break;
}
pos--;
}
while (pos >= 0) {
for (let i = 0; i < commits[pos].parents.length; i++) {
if (connected.includes(commits[pos].parents[i].commit)) {
connected.push(commits[pos].commit);
break;
}
}
--pos;
}
return connected;
},
_computeSubmittedTogetherClass(submittedTogether) {
if (!submittedTogether || (
submittedTogether.changes.length === 0 &&
!submittedTogether.non_visible_changes)) {
return 'hidden';
}
return '';
},
_computeNonVisibleChangesNote(n) {
const noun = n === 1 ? 'change' : 'changes';
return `(+ ${n} non-visible ${noun})`;
},
});
})();