Merge "Update rebase dialog to give parent autocomplete suggestions"
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
index 481cd76..f3286f2 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.html
@@ -132,6 +132,7 @@
<gr-overlay id="overlay" with-backdrop>
<gr-confirm-rebase-dialog id="confirmRebase"
class="confirmDialog"
+ change-number="[[change._number]]"
on-confirm="_handleRebaseConfirm"
on-cancel="_handleConfirmDialogCancel"
branch="[[change.branch]]"
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
index b2a6f0d..92dc887 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
@@ -173,7 +173,7 @@
*/
properties: {
- /** @type {{ branch: string, project: string }} */
+ /** @type {{ _number: number, branch: string, project: string }} */
change: Object,
actions: {
type: Object,
@@ -802,6 +802,7 @@
switch (key) {
case RevisionActions.REBASE:
this._showActionDialog(this.$.confirmRebase);
+ this.$.confirmRebase.fetchRecentChanges();
break;
case RevisionActions.CHERRYPICK:
this._handleCherrypickTap();
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
index 62b4626..df2fbcb 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
@@ -306,6 +306,9 @@
test('rebase change', done => {
const fireActionStub = sandbox.stub(element, '_fireAction');
+ const fetchChangesStub = sandbox.stub(element.$.confirmRebase,
+ 'fetchRecentChanges').returns(Promise.resolve([]));
+ element._hasKnownChainState = true;
flush(() => {
const rebaseButton = element.$$('gr-button[data-action-key="rebase"]');
MockInteractions.tap(rebaseButton);
@@ -318,6 +321,7 @@
method: 'POST',
title: 'Rebase onto tip of branch or parent change',
};
+ assert.isTrue(fetchChangesStub.called);
// rebase on other
element.$.confirmRebase.base = '1234';
element._handleRebaseConfirm();
@@ -340,6 +344,22 @@
});
});
+ test(`rebase dialog gets recent changes each time it's opened`, done => {
+ const fetchChangesStub = sandbox.stub(element.$.confirmRebase,
+ 'fetchRecentChanges').returns(Promise.resolve([]));
+ element._hasKnownChainState = true;
+ const rebaseButton = element.$$('gr-button[data-action-key="rebase"]');
+ MockInteractions.tap(rebaseButton);
+ assert.isTrue(fetchChangesStub.calledOnce);
+
+ flush(() => {
+ element.$.confirmRebase.fire('cancel');
+ MockInteractions.tap(rebaseButton);
+ assert.isTrue(fetchChangesStub.calledTwice);
+ done();
+ });
+ });
+
test('two dialogs are not shown at the same time', done => {
element._hasKnownChainState = true;
flush(() => {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.html b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.html
index 582a03c..4370d7e 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.html
@@ -15,7 +15,9 @@
-->
<link rel="import" href="../../../bower_components/polymer/polymer.html">
+<link rel="import" href="../../shared/gr-autocomplete/gr-autocomplete.html">
<link rel="import" href="../../shared/gr-confirm-dialog/gr-confirm-dialog.html">
+<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../../../styles/shared-styles.html">
<dom-module id="gr-confirm-rebase-dialog">
@@ -49,6 +51,7 @@
}
</style>
<gr-confirm-dialog
+ id="confirmDialog"
confirm-label="Rebase"
on-confirm="_handleConfirmTap"
on-cancel="_handleCancelTap">
@@ -98,15 +101,18 @@
</label>
</div>
<div class="parentRevisionContainer">
- <input is="iron-input"
- type="text"
+ <gr-autocomplete
id="parentInput"
- bind-value="{{base}}"
+ query="[[_query]]"
+ text="{{_inputText}}"
on-tap="_handleEnterChangeNumberTap"
+ on-commit="_handleBaseSelected"
placeholder="Change number">
+ </gr-autocomplete>
</div>
</div>
</gr-confirm-dialog>
+ <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-confirm-rebase-dialog.js"></script>
</dom-module>
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
index eb0fa17..e4f6e97 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.js
@@ -36,14 +36,62 @@
* @type {?string} */
base: String,
branch: String,
+ changeNumber: Number,
hasParent: Boolean,
rebaseOnCurrent: Boolean,
+ _inputText: String,
+ _query: {
+ type: Function,
+ value() {
+ return this._getChangeSuggestions.bind(this);
+ },
+ },
+ _recentChanges: Array,
},
observers: [
'_updateSelectedOption(rebaseOnCurrent, hasParent)',
],
+ // This is called by gr-change-actions every time the rebase dialog is
+ // re-opened. Unlike other autocompletes that make a request with each
+ // updated input, this one gets all recent changes once and then filters
+ // them by the input. The query is re-run each time the dialog is opened
+ // in case there are new/updated changes in the generic query since the
+ // last time it was run.
+ fetchRecentChanges() {
+ return this.$.restAPI.getChanges(null, `is:open -age:90d`)
+ .then(response => {
+ const changes = [];
+ for (const key in response) {
+ if (!response.hasOwnProperty(key)) { continue; }
+ changes.push({
+ name: `${response[key]._number}: ${response[key].subject}`,
+ value: response[key]._number,
+ });
+ }
+ this._recentChanges = changes;
+ return this._recentChanges;
+ });
+ },
+
+ _getRecentChanges() {
+ if (this._recentChanges) {
+ return Promise.resolve(this._recentChanges);
+ }
+ return this.fetchRecentChanges();
+ },
+
+ _getChangeSuggestions(input) {
+ return this._getRecentChanges().then(changes =>
+ this._filterChanges(input, changes));
+ },
+
+ _filterChanges(input, changes) {
+ return changes.filter(change => change.name.includes(input) &&
+ change.value !== this.changeNumber);
+ },
+
_displayParentOption(rebaseOnCurrent, hasParent) {
return hasParent && rebaseOnCurrent;
},
@@ -58,11 +106,13 @@
_handleConfirmTap(e) {
e.preventDefault();
+ this._inputText = '';
this.fire('confirm', null, {bubbles: false});
},
_handleCancelTap(e) {
e.preventDefault();
+ this._inputText = '';
this.fire('cancel', null, {bubbles: false});
},
@@ -85,6 +135,10 @@
this.base = null;
},
+ _handleBaseSelected(e) {
+ this.base = e.detail.value;
+ },
+
_handleEnterChangeNumberTap() {
this.$.rebaseOnOtherInput.checked = true;
},
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
index 0ea7c49..ccfc368 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.html
@@ -34,9 +34,15 @@
<script>
suite('gr-confirm-rebase-dialog tests', () => {
let element;
+ let sandbox;
setup(() => {
element = fixture('basic');
+ sandbox = sinon.sandbox.create();
+ });
+
+ teardown(() => {
+ sandbox.restore();
});
test('controls with parent and rebase on current available', () => {
@@ -82,5 +88,88 @@
assert.isTrue(element.$.rebaseOnTip.hasAttribute('hidden'));
assert.isFalse(element.$.tipUpToDateMsg.hasAttribute('hidden'));
});
+
+ test('input cleared on cancel or submit', () => {
+ element._inputText = '123';
+ element.$.confirmDialog.fire('confirm');
+ assert.equal(element._inputText, '');
+
+ element._inputText = '123';
+ element.$.confirmDialog.fire('cancel');
+ assert.equal(element._inputText, '');
+ });
+
+ suite('parent suggestions', () => {
+ let recentChanges;
+ setup(() => {
+ recentChanges = [
+ {
+ name: '123: my first awesome change',
+ value: 123,
+ },
+ {
+ name: '124: my second awesome change',
+ value: 124,
+ },
+ {
+ name: '245: my third awesome change',
+ value: 245,
+ },
+ ];
+
+ sandbox.stub(element.$.restAPI, 'getChanges').returns(Promise.resolve(
+ [
+ {
+ _number: 123,
+ subject: 'my first awesome change',
+ },
+ {
+ _number: 124,
+ subject: 'my second awesome change',
+ },
+ {
+ _number: 245,
+ subject: 'my third awesome change',
+ },
+ ]
+ ));
+ });
+
+ test('_getRecentChanges', () => {
+ sandbox.spy(element, '_getRecentChanges');
+ return element._getRecentChanges().then(() => {
+ assert.deepEqual(element._recentChanges, recentChanges);
+ assert.equal(element.$.restAPI.getChanges.callCount, 1);
+ // When called a second time, should not re-request recent changes.
+ element._getRecentChanges();
+ }).then(() => {
+ assert.equal(element._getRecentChanges.callCount, 2);
+ assert.equal(element.$.restAPI.getChanges.callCount, 1);
+ });
+ });
+
+ test('_filterChanges', () => {
+ assert.equal(element._filterChanges('123', recentChanges).length, 1);
+ assert.equal(element._filterChanges('12', recentChanges).length, 2);
+ assert.equal(element._filterChanges('awesome', recentChanges).length,
+ 3);
+ assert.equal(element._filterChanges('third', recentChanges).length,
+ 1);
+
+ element.changeNumber = 123;
+ assert.equal(element._filterChanges('123', recentChanges).length, 0);
+ assert.equal(element._filterChanges('124', recentChanges).length, 1);
+ assert.equal(element._filterChanges('awesome', recentChanges).length,
+ 2);
+ });
+
+ test('input text change triggers function', () => {
+ sandbox.spy(element, '_getRecentChanges');
+ element._inputText = '1';
+ assert.isTrue(element._getRecentChanges.calledOnce);
+ element._inputText = '12';
+ assert.isTrue(element._getRecentChanges.calledTwice);
+ });
+ });
});
</script>