Add submit button to PolyGerrit
+ Lays the groundwork for other actions as well.
+ Another change seemingly unrelated is within gr-reply-dropdown,
which is in here because when a change is submitted, the
permittedLabels property on the change goes to {}, which needs
to be accounted for.
Change-Id: I14c4c62ad7e52df6d56894abb38b708d81964d1b
diff --git a/polygerrit-ui/app/elements/gr-change-actions.html b/polygerrit-ui/app/elements/gr-change-actions.html
new file mode 100644
index 0000000..c37a931
--- /dev/null
+++ b/polygerrit-ui/app/elements/gr-change-actions.html
@@ -0,0 +1,138 @@
+<!--
+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="gr-ajax.html">
+<link rel="import" href="gr-request.html">
+
+<dom-module id="gr-change-actions">
+ <template>
+ <style>
+ :host {
+ display: block;
+ }
+ button {
+ background-color: #448aff;
+ border: none;
+ border-radius: 2px;
+ color: #fff;
+ cursor: pointer;
+ font: inherit;
+ padding: .5em .75em;
+ }
+ button[disabled] {
+ opacity: .5;
+ }
+ </style>
+ <gr-ajax id="actionsXHR"
+ url="[[_computeActionsPath(changeNum, patchNum)]]"
+ last-response="{{_actions}}"
+ loading="{{_loading}}"></gr-ajax>
+ <div>
+ <template is="dom-repeat" items="[[_computeActionValues(_actions)]]" as="action">
+ <button title$="[[action.title]]"
+ hidden$="[[!action.enabled]]"
+ data-action-key$="[[action.__key]]"
+ disabled$="[[_loading]]"
+ on-tap="_handleActionTap">[[action.label]]</button>
+ </template>
+ </div>
+ </template>
+ <script>
+ (function() {
+ 'use strict';
+
+ Polymer({
+ is: 'gr-change-actions',
+
+ /**
+ * Fired when the change should be reloaded.
+ *
+ * @event reload-change
+ */
+
+ properties: {
+ changeNum: String,
+ patchNum: String,
+ _actions: {
+ type: Object,
+ observer: '_actionsChanged',
+ },
+ _loading: {
+ type: Boolean,
+ value: false,
+ },
+ },
+
+ reload: function() {
+ if (!!this.changeNum && !!this.patchNum) {
+ this.$.actionsXHR.generateRequest();
+ }
+ },
+
+ _actionsChanged: function(actions) {
+ this.hidden = actions.submit == null;
+ },
+
+ _computeActionsPath: function(changeNum, patchNum) {
+ return Changes.baseURL(changeNum, patchNum) + '/actions';
+ },
+
+ _computeActionValues: function(actions) {
+ var result = [];
+ for (var a in actions) {
+ // TODO(andybons): Add the rest of the actions.
+ if (a != 'submit') { continue; }
+ actions[a].__key = a;
+ result.push(actions[a]);
+ }
+ return result;
+ },
+
+ _handleActionTap: function(e) {
+ e.preventDefault();
+ var el = Polymer.dom(e).rootTarget;
+ var key = el.getAttribute('data-action-key');
+ if (key == 'submit') {
+ this._submitChange('/' + key, this._actions[key]);
+ }
+ },
+
+ _submitChange: function(endpoint, action) {
+ this._send(action.method, {}, endpoint).then(
+ function() {
+ this.fire('reload-change', null, {bubbles: false});
+ }.bind(this)).catch(function(err) {
+ alert('Oops. Something went wrong. Check the console and bug the ' +
+ 'PolyGerrit team for assistance.');
+ throw err;
+ });
+ },
+
+ _send: function(method, payload, actionEndpoint) {
+ var xhr = document.createElement('gr-request');
+ this._xhrPromise = xhr.send({
+ method: method,
+ url: Changes.baseURL(this.changeNum, this.patchNum) + actionEndpoint,
+ body: payload,
+ });
+
+ return this._xhrPromise;
+ },
+ });
+ })();
+ </script>
+</dom-module>
diff --git a/polygerrit-ui/app/elements/gr-change-view.html b/polygerrit-ui/app/elements/gr-change-view.html
index 81034bc..fbf005c 100644
--- a/polygerrit-ui/app/elements/gr-change-view.html
+++ b/polygerrit-ui/app/elements/gr-change-view.html
@@ -17,6 +17,7 @@
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
<link rel="import" href="gr-ajax.html">
+<link rel="import" href="gr-change-actions.html">
<link rel="import" href="gr-date-formatter.html">
<link rel="import" href="gr-file-list.html">
<link rel="import" href="gr-linked-text.html">
@@ -112,6 +113,9 @@
.notApproved {
background-color: #ffd4d4;
}
+ gr-change-actions {
+ margin-top: 1em;
+ }
.summary {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
@@ -229,6 +233,10 @@
</tr>
</template>
</table>
+ <gr-change-actions id="actions"
+ change-num="[[_changeNum]]"
+ patch-num="[[_patchNum]]"
+ on-reload-change="_reload"></gr-change-actions>
</section>
<section class="summary">
<gr-linked-text pre
@@ -457,16 +465,17 @@
_reload: function() {
var detailCompletes = this.$.detailXHR.generateRequest().completes;
this.$.commentsXHR.generateRequest();
- var reloadCommitInfoAndFileList = function() {
+ var reloadPatchNumDependentResources = function() {
this.$.commitInfoXHR.generateRequest();
+ this.$.actions.reload();
this.$.fileList.reload();
}.bind(this);
if (this._patchNum) {
- reloadCommitInfoAndFileList();
+ reloadPatchNumDependentResources();
} else {
// The patch number is reliant on the change detail request.
- detailCompletes.then(reloadCommitInfoAndFileList);
+ detailCompletes.then(reloadPatchNumDependentResources);
}
},
diff --git a/polygerrit-ui/app/elements/gr-reply-dropdown.html b/polygerrit-ui/app/elements/gr-reply-dropdown.html
index b65cbcb..12ab5b3 100644
--- a/polygerrit-ui/app/elements/gr-reply-dropdown.html
+++ b/polygerrit-ui/app/elements/gr-reply-dropdown.html
@@ -249,7 +249,9 @@
}
}
- for (var i = 0; i < permittedLabels[labelName].length; i++) {
+ var len = permittedLabels[labelName] != null ?
+ permittedLabels[labelName].length : 0;
+ for (var i = 0; i < len; i++) {
var val = parseInt(permittedLabels[labelName][i], 10);
if (val == labelValue) {
return i;
diff --git a/polygerrit-ui/app/test/gr-change-actions-test.html b/polygerrit-ui/app/test/gr-change-actions-test.html
new file mode 100644
index 0000000..69e2491
--- /dev/null
+++ b/polygerrit-ui/app/test/gr-change-actions-test.html
@@ -0,0 +1,119 @@
+<!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-change-actions</title>
+
+<script src="../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
+<script src="../../bower_components/web-component-tester/browser.js"></script>
+<script src="../scripts/changes.js"></script>
+<script src="../scripts/util.js"></script>
+
+<link rel="import" href="../../bower_components/iron-test-helpers/iron-test-helpers.html">
+<link rel="import" href="../elements/gr-change-actions.html">
+
+<test-fixture id="basic">
+ <template>
+ <gr-change-actions></gr-change-actions>
+ </template>
+</test-fixture>
+
+<script>
+ suite('gr-change-actions tests', function() {
+ var element;
+ var server;
+
+ setup(function() {
+ element = fixture('basic');
+ server = sinon.fakeServer.create();
+
+ server.respondWith(
+ 'GET',
+ '/changes/42/revisions/2/actions',
+ [
+ 200,
+ { 'Content-Type': 'application/json' },
+ ')]}\'\n' +
+ JSON.stringify({
+ cherrypick: {
+ method: 'POST',
+ label: 'Cherry Pick',
+ title: 'Cherry pick change to a different branch',
+ enabled: true
+ },
+ rebase: {
+ method: 'POST',
+ label: 'Rebase',
+ title: 'Rebase onto tip of branch or parent change'
+ },
+ submit: {
+ method: 'POST',
+ label: 'Submit',
+ title: 'Submit patch set 1 into master',
+ enabled: true
+ }
+ }),
+ ]
+ );
+
+ server.respondWith(
+ 'POST',
+ '/changes/42/revisions/2/submit',
+ [
+ 200,
+ { 'Content-Type': 'application/json' },
+ ')]}\'\n{}', // The response is not used by the element.
+ ]
+ );
+ });
+
+ test('submit button shows', function(done) {
+ element.changeNum = '42';
+ element.patchNum = '2';
+ element.reload();
+
+ server.respond();
+
+ element.async(function() {
+ var buttonEls = Polymer.dom(element.root).querySelectorAll('button');
+ assert.equal(buttonEls.length, 1);
+ assert.isFalse(element.hidden);
+ done();
+ }, 1);
+ });
+
+ test('submit change', function(done) {
+ element.changeNum = '42';
+ element.patchNum = '2';
+ element.reload();
+
+ server.respond();
+
+ element.async(function() {
+ var submitButton = element.$$('button[data-action-key="submit"]');
+ assert.ok(submitButton);
+ MockInteractions.tap(submitButton);
+ server.respond();
+
+ // Upon success it should fire the reload-change event.
+ element.addEventListener('reload-change', function(e) {
+ done();
+ });
+ }, 1);
+ });
+ });
+</script>
diff --git a/polygerrit-ui/app/test/index.html b/polygerrit-ui/app/test/index.html
index 85c0e1d..b1f6128 100644
--- a/polygerrit-ui/app/test/index.html
+++ b/polygerrit-ui/app/test/index.html
@@ -24,6 +24,7 @@
var testFiles = [];
[ 'gr-account-dropdown-test.html',
+ 'gr-change-actions-test.html',
'gr-change-list-item-test.html',
'gr-change-list-test.html',
'gr-change-view-test.html',