Merge "Initial add of related changes to the change view"

This commit is contained in:
Dave Borowitz 2016-02-09 17:46:24 +00:00 committed by Gerrit Code Review
commit ea737faed8
4 changed files with 600 additions and 2 deletions

View File

@ -25,6 +25,7 @@ limitations under the License.
<link rel="import" href="gr-file-list.html">
<link rel="import" href="gr-linked-text.html">
<link rel="import" href="gr-messages-list.html">
<link rel="import" href="gr-related-changes-list.html">
<link rel="import" href="gr-reply-dropdown.html">
<link rel="import" href="gr-reviewer-list.html">
@ -133,6 +134,10 @@ limitations under the License.
gr-file-list {
padding: 0 var(--default-horizontal-margin) 10px;
}
gr-related-changes-list {
border-top: 1px solid #ddd;
padding: 0 var(--default-horizontal-margin);
}
</style>
<gr-ajax id="detailXHR"
url="[[_computeDetailPath(_changeNum)]]"
@ -256,6 +261,10 @@ limitations under the License.
patch-num="[[_patchNum]]"
comments="[[_comments]]"
selected-index="{{viewState.selectedFileIndex}}"></gr-file-list>
<gr-related-changes-list id="relatedChanges"
change="[[_change]]"
server-config="[[serverConfig]]"
patch-num="[[_patchNum]]"></gr-related-changes-list>
<gr-messages-list id="messageList"
change-num="[[_changeNum]]"
messages="[[_change.messages]]"
@ -540,14 +549,20 @@ limitations under the License.
this.$.fileList.reload(),
]);
}.bind(this);
var reloadDetailDependentResources = function() {
return this.$.relatedChanges.reload();
}.bind(this);
this._resetHeaderEl();
if (this._patchNum) {
return reloadPatchNumDependentResources();
return reloadPatchNumDependentResources().then(function() {
return detailCompletes;
}).then(reloadDetailDependentResources);
} else {
// The patch number is reliant on the change detail request.
return detailCompletes.then(reloadPatchNumDependentResources);
return detailCompletes.then(reloadPatchNumDependentResources).then(
reloadDetailDependentResources);
}
},

View File

@ -0,0 +1,365 @@
<!--
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.
-->
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../behaviors/rest-client-behavior.html">
<link rel="import" href="gr-ajax.html">
<dom-module id="gr-related-changes-list">
<template>
<style>
:host {
display: block;
}
h3 {
margin: .5em 0 0;
}
section:first-of-type {
margin-top: .5em;
}
section:last-of-type {
margin-bottom: 2em;
}
section {
margin: 1em 0;
}
a {
display: block;
}
.relatedChanges a {
display: inline-block;
}
.strikethrough {
color: #666;
text-decoration: line-through;
}
.status {
color: #666;
font-weight: bold;
}
.notCurrent {
color: #e65100;
}
.indirectAncestor {
color: #33691e;
}
.submittable {
color: #1b5e20;
}
.hidden {
display: none;
}
</style>
<gr-ajax id="relatedXHR"
url="[[_computeRelatedURL(change._number, patchNum)]]"
last-response="{{_relatedResponse}}"></gr-ajax>
<gr-ajax id="submittedTogetherXHR"
url="[[_computeSubmittedTogetherURL(change._number)]]"
last-response="{{_submittedTogether}}"></gr-ajax>
<gr-ajax id="conflictsXHR"
url="/changes/"
params="[[_computeConflictsQueryParams(change._number)]]"
last-response="{{_conflicts}}"></gr-ajax>
<gr-ajax id="cherryPicksXHR"
url="/changes/"
params="[[_computeCherryPicksQueryParams(change.project, change.change_id, change._number)]]"
last-response="{{_cherryPicks}}"></gr-ajax>
<gr-ajax id="sameTopicXHR"
url="/changes/"
params="[[_computeSameTopicQueryParams(change.topic)]]"
last-response="{{_sameTopic}}"></gr-ajax>
<h3>Related changes</h3>
<div hidden$="[[!_loading]]">Loading...</div>
<section class="relatedChanges" hidden$="[[!_relatedResponse.changes.length]]" hidden>
<h4>Relation Chain</h4>
<template is="dom-repeat" items="[[_relatedResponse.changes]]" as="change">
<div>
<a href$="[[_computeChangeURL(change._change_number, change._revision_number)]]"
class$="[[_computeLinkClass(change)]]"
target="_blank">[[change.commit.subject]]</a>
<span class$="[[_computeChangeStatusClass(change)]]">
([[_computeChangeStatus(change)]])
</span>
</div>
</template>
</section>
<section hidden$="[[!_submittedTogether.length]]" hidden>
<h4>Submitted together</h4>
<template is="dom-repeat" items="[[_submittedTogether]]" as="change">
<a href$="[[_computeChangeURL(change._number)]]"
class$="[[_computeLinkClass(change)]]"
target="_blank">[[change.project]]: [[change.branch]]: [[change.subject]]</a>
</template>
</section>
<section hidden="[[!_sameTopic.length]]" hidden>
<h4>Same topic</h4>
<template is="dom-repeat" items="[[_sameTopic]]" as="change">
<a href$="[[_computeChangeURL(change._number)]]"
class$="[[_computeLinkClass(change)]]"
target="_blank">[[change.project]]: [[change.branch]]: [[change.subject]]</a>
</template>
</section>
<section hidden="[[!_conflicts.length]]" hidden>
<h4>Merge conflicts</h4>
<template is="dom-repeat" items="[[_conflicts]]" as="change">
<a href$="[[_computeChangeURL(change._number)]]"
class$="[[_computeLinkClass(change)]]"
target="_blank">[[change.subject]]</a>
</template>
</section>
<section hidden="[[!_cherryPicks.length]]" hidden>
<h4>Cherry picks</h4>
<template is="dom-repeat" items="[[_cherryPicks]]" as="change">
<a href$="[[_computeChangeURL(change._number)]]"
class$="[[_computeLinkClass(change)]]"
target="_blank">[[change.subject]]</a>
</template>
</section>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'gr-related-changes-list',
properties: {
change: Object,
patchNum: String,
serverConfig: {
type: Object,
observer: '_serverConfigChanged',
},
hidden: {
type: Boolean,
value: false,
reflectToAttribute: true,
},
_loading: Boolean,
_resolveServerConfigReady: Function,
_serverConfigReady: {
type: Object,
value: function() {
return new Promise(function(resolve) {
this._resolveServerConfigReady = resolve;
}.bind(this));
}
},
_connectedRevisions: {
type: Array,
computed: '_computeConnectedRevisions(change, patchNum, ' +
'_relatedResponse.changes)',
},
_relatedResponse: Object,
_submittedTogether: Array,
_conflicts: Array,
_cherryPicks: Array,
_sameTopic: Array,
},
behaviors: [
Gerrit.RESTClientBehavior,
],
observers: [
'_resultsChanged(_relatedResponse.changes, _submittedTogether, ' +
'_conflicts, _cherryPicks, _sameTopic)',
],
reload: function() {
if (!this.change || !this.patchNum) {
return Promise.resolve();
}
this._loading = true;
var promises = [
this.$.relatedXHR.generateRequest().completes,
this.$.submittedTogetherXHR.generateRequest().completes,
this.$.conflictsXHR.generateRequest().completes,
this.$.cherryPicksXHR.generateRequest().completes,
];
return this._serverConfigReady.then(function() {
if (this.change.topic &&
!this.serverConfig.change.submit_whole_topic) {
return this.$.sameTopicXHR.generateRequest().completes;
} else {
this._sameTopic = [];
}
return Promise.resolve();
}.bind(this)).then(Promise.all(promises)).then(function() {
this._loading = false;
}.bind(this));
},
_computeRelatedURL: function(changeNum, patchNum) {
return this.changeBaseURL(changeNum, patchNum) + '/related';
},
_computeSubmittedTogetherURL: function(changeNum) {
return this.changeBaseURL(changeNum) + '/submitted_together';
},
_computeConflictsQueryParams: function(changeNum) {
var options = this.listChangesOptionsToHex(
this.ListChangesOption.CURRENT_REVISION,
this.ListChangesOption.CURRENT_COMMIT
);
return {
O: options,
q: 'status:open is:mergeable conflicts:' + changeNum,
};
},
_computeCherryPicksQueryParams: function(project, changeID, changeNum) {
var options = this.listChangesOptionsToHex(
this.ListChangesOption.CURRENT_REVISION,
this.ListChangesOption.CURRENT_COMMIT
);
var query = [
'project:' + project,
'change:' + changeID,
'-change:' + changeNum,
'-is:abandoned',
].join(' ');
return {
O: options,
q: query
}
},
_computeSameTopicQueryParams: function(topic) {
var options = this.listChangesOptionsToHex(
this.ListChangesOption.LABELS,
this.ListChangesOption.CURRENT_REVISION,
this.ListChangesOption.CURRENT_COMMIT,
this.ListChangesOption.DETAILED_LABELS
);
return {
O: options,
q: 'status:open topic:' + topic,
};
},
_computeChangeURL: function(changeNum, patchNum) {
var urlStr = '/c/' + changeNum;
if (patchNum != null) {
urlStr += '/' + patchNum;
}
return urlStr;
},
_computeLinkClass: function(change) {
if (change.status == this.ChangeStatus.ABANDONED) {
return 'strikethrough';
}
},
_computeChangeStatusClass: function(change) {
var 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: function(change) {
switch (change.status) {
case this.ChangeStatus.MERGED:
return 'Merged';
case this.ChangeStatus.ABANDONED:
return 'Abandoned';
case this.ChangeStatus.DRAFT:
return 'Draft';
}
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 ''
},
_serverConfigChanged: function(config) {
this._resolveServerConfigReady(config);
},
_resultsChanged: function(related, submittedTogether, conflicts,
cherryPicks, sameTopic) {
var results = [
related,
submittedTogether,
conflicts,
cherryPicks,
sameTopic
];
for (var i = 0; i < results.length; i++) {
if (results[i].length > 0) {
this.hidden = false;
return;
}
}
this.hidden = true;
},
_isIndirectAncestor: function(change) {
return this._connectedRevisions.indexOf(change.commit.commit) == -1;
},
_computeConnectedRevisions: function(change, patchNum, relatedChanges) {
var connected = [];
var changeRevision;
for (var rev in change.revisions) {
if (change.revisions[rev]._number == patchNum) {
changeRevision = rev;
}
}
var commits = relatedChanges.map(function(c) { return c.commit; });
var pos = commits.length - 1;
while (pos >= 0) {
var commit = commits[pos].commit;
connected.push(commit);
if (commit == changeRevision) {
break;
}
pos--;
}
while (pos >= 0) {
for (var i = 0; i < commits[pos].parents.length; i++) {
if (connected.indexOf(commits[pos].parents[i].commit) != -1) {
connected.push(commits[pos].commit);
break;
}
}
--pos;
}
return connected;
},
});
})();
</script>
</dom-module>

View File

@ -0,0 +1,217 @@
<!DOCTYPE html>
<!--
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.
-->
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-related-changes-list</title>
<script src="../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<script src="../bower_components/web-component-tester/browser.js"></script>
<link rel="import" href="../bower_components/iron-test-helpers/iron-test-helpers.html">
<link rel="import" href="../elements/gr-related-changes-list.html">
<test-fixture id="basic">
<template>
<gr-related-changes-list></gr-related-changes-list>
</template>
</test-fixture>
<script>
suite('gr-related-changes-list tests', function() {
var element;
setup(function() {
element = fixture('basic');
});
test('connected revisions', function() {
var change = {
revisions: {
'e3c6d60783bfdec9ebae7dcfec4662360433449e': {
_number: 1,
},
'26e5e4c9c7ae31cbd876271cca281ce22b413997': {
_number: 2,
},
'bf7884d695296ca0c91702ba3e2bc8df0f69a907': {
_number: 7,
},
'b5fc49f2e67d1889d5275cac04ad3648f2ec7fe3': {
_number: 5,
},
'd6bcee67570859ccb684873a85cf50b1f0e96fda': {
_number: 6,
},
'cc960918a7f90388f4a9e05753d0f7b90ad44546': {
_number: 3,
},
'9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6': {
_number: 4,
}
}
};
var patchNum = 7;
var relatedChanges = [
{
commit: {
commit: '2cebeedfb1e80f4b872d0a13ade529e70652c0c8',
parents: [
{
commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd'
}
],
},
},
{
commit: {
commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd',
parents: [
{
commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb'
}
],
},
},
{
commit: {
commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb',
parents: [
{
commit: 'b0ccb183494a8e340b8725a2dc553967d61e6dae'
}
],
},
},
{
commit: {
commit: 'b0ccb183494a8e340b8725a2dc553967d61e6dae',
parents: [
{
commit: 'bf7884d695296ca0c91702ba3e2bc8df0f69a907'
}
],
},
},
{
commit: {
commit: 'bf7884d695296ca0c91702ba3e2bc8df0f69a907',
parents: [
{
commit: '613bc4f81741a559c6667ac08d71dcc3348f73ce'
}
],
},
},
{
commit: {
commit: '613bc4f81741a559c6667ac08d71dcc3348f73ce',
parents: [
{
commit: '455ed9cd27a16bf6991f04dcc57ef575dc4d5e75'
}
],
},
}
];
var connectedChanges =
element._computeConnectedRevisions(change, patchNum, relatedChanges);
assert.deepEqual(connectedChanges, [
'613bc4f81741a559c6667ac08d71dcc3348f73ce',
'bf7884d695296ca0c91702ba3e2bc8df0f69a907',
'bf7884d695296ca0c91702ba3e2bc8df0f69a907',
'b0ccb183494a8e340b8725a2dc553967d61e6dae',
'6c71f9e86ba955a7e01e2088bce0050a90eb9fbb',
'87ed20b241576b620bbaa3dfd47715ce6782b7dd',
'2cebeedfb1e80f4b872d0a13ade529e70652c0c8',
]);
patchNum = 4;
relatedChanges = [
{
commit: {
commit: '2cebeedfb1e80f4b872d0a13ade529e70652c0c8',
parents: [
{
commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd'
}
],
},
},
{
commit: {
commit: '87ed20b241576b620bbaa3dfd47715ce6782b7dd',
parents: [
{
commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb'
}
],
},
},
{
commit: {
commit: '6c71f9e86ba955a7e01e2088bce0050a90eb9fbb',
parents: [
{
commit: 'b0ccb183494a8e340b8725a2dc553967d61e6dae'
}
],
},
},
{
commit: {
commit: 'a3e5d9d4902b915a39e2efba5577211b9b3ebe7b',
parents: [
{
commit: '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6'
}
],
},
},
{
commit: {
commit: '9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6',
parents: [
{
commit: 'af815dac54318826b7f1fa468acc76349ffc588e'
}
],
},
},
{
commit: {
commit: 'af815dac54318826b7f1fa468acc76349ffc588e',
parents: [
{
commit: '58f76e406e24cb8b0f5d64c7f5ac1e8616d0a22c'
}
],
},
}
];
connectedChanges =
element._computeConnectedRevisions(change, patchNum, relatedChanges);
assert.deepEqual(connectedChanges, [
'af815dac54318826b7f1fa468acc76349ffc588e',
'9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6',
'9e593f6dcc2c0785a2ad2c895a34ad2aa9a0d8b6',
'a3e5d9d4902b915a39e2efba5577211b9b3ebe7b',
]);
});
});
</script>

View File

@ -45,6 +45,7 @@ limitations under the License.
'gr-message-test.html',
'gr-messages-list-test.html',
'gr-patch-range-select-test.html',
'gr-related-changes-list-test.html',
'gr-reply-dropdown-test.html',
'gr-reviewer-list-test.html',
'gr-search-bar-test.html',