Merge "Update the patchset description editor to use a linked chip"
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
index da3a547..f46af09 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.html
@@ -21,6 +21,7 @@
<link rel="import" href="../../diff/gr-patch-range-select/gr-patch-range-select.html">
<link rel="import" href="../../edit/gr-edit-controls/gr-edit-controls.html">
<link rel="import" href="../../shared/gr-editable-label/gr-editable-label.html">
+<link rel="import" href="../../shared/gr-linked-chip/gr-linked-chip.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../../shared/gr-select/gr-select.html">
<link rel="import" href="../../shared/gr-button/gr-button.html">
@@ -100,6 +101,9 @@
gr-button.selected iron-icon {
color: var(--color-link);
}
+ gr-linked-chip {
+ --linked-chip-text-color: black;
+ }
.expanded #collapseBtn,
.openFile .fileViewActions {
align-items: center;
@@ -164,14 +168,28 @@
</span>
<span class="container descriptionContainer hideOnEdit">
<span class="separator"></span>
- <gr-editable-label
- id="descriptionLabel"
- class="descriptionLabel"
- label-text="Add patchset description"
- value="[[_computePatchSetDescription(change, patchNum)]]"
- placeholder="[[_computeDescriptionPlaceholder(_descriptionReadOnly)]]"
- read-only="[[_descriptionReadOnly]]"
- on-changed="_handleDescriptionChanged"></gr-editable-label>
+ <template
+ is="dom-if"
+ if="[[_patchsetDescription]]">
+ <gr-linked-chip
+ id="descriptionChip"
+ text="[[_patchsetDescription]]"
+ removable="[[!_descriptionReadOnly]]"
+ on-remove="_handleDescriptionRemoved"></gr-linked-chip>
+ </template>
+ <template
+ is="dom-if"
+ if="[[!_patchsetDescription]]">
+ <gr-editable-label
+ id="descriptionLabel"
+ uppercase
+ class="descriptionLabel"
+ label-text="Add patchset description"
+ value="[[_patchsetDescription]]"
+ placeholder="[[_computeDescriptionPlaceholder(_descriptionReadOnly)]]"
+ read-only="[[_descriptionReadOnly]]"
+ on-changed="_handleDescriptionChanged"></gr-editable-label>
+ </template>
</span>
</div>
<div class$="rightControls [[_computeExpandedClass(filesExpanded)]]">
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
index e0b4d6c..123b156 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.js
@@ -48,6 +48,10 @@
readOnly: true,
value: 225,
},
+ _patchsetDescription: {
+ type: String,
+ value: '',
+ },
_descriptionReadOnly: {
type: Boolean,
computed: '_computeDescriptionReadOnly(loggedIn, change, account)',
@@ -67,6 +71,10 @@
Gerrit.PatchSetBehavior,
],
+ observers: [
+ '_computePatchSetDescription(change, patchNum)',
+ ],
+
_expandAllDiffs() {
this._expanded = true;
this.fire('expand-diffs');
@@ -111,10 +119,14 @@
_computePatchSetDescription(change, patchNum) {
const rev = this.getRevisionByPatchNum(change.revisions, patchNum);
- return (rev && rev.description) ?
+ this._patchsetDescription = (rev && rev.description) ?
rev.description.substring(0, PATCH_DESC_MAX_LENGTH) : '';
},
+ _handleDescriptionRemoved(e) {
+ return this._updateDescription('', e);
+ },
+
/**
* @param {!Object} revisions The revisions object keyed by revision hashes
* @param {?Object} patchSet A revision already fetched from {revisions}
@@ -131,15 +143,31 @@
_handleDescriptionChanged(e) {
const desc = e.detail.trim();
+ this._updateDescription(desc, e);
+ },
+
+ /**
+ * Update the patchset description with the rest API.
+ * @param {string} desc
+ * @param {?(Event|Node)} e
+ * @return {!Promise}
+ */
+ _updateDescription(desc, e) {
+ const target = Polymer.dom(e).rootTarget;
+ if (target) { target.disabled = true; }
const rev = this.getRevisionByPatchNum(this.change.revisions,
this.patchNum);
const sha = this._getPatchsetHash(this.change.revisions, rev);
- this.$.restAPI.setDescription(this.changeNum,
- this.patchNum, desc)
+ return this.$.restAPI.setDescription(this.changeNum, this.patchNum, desc)
.then(res => {
if (res.ok) {
+ if (target) { target.disabled = false; }
this.set(['_change', 'revisions', sha, 'description'], desc);
+ this._patchsetDescription = desc;
}
+ }).catch(err => {
+ if (target) { target.disabled = false; }
+ return;
});
},
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
index d47023f..8dbb06f 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.html
@@ -96,10 +96,9 @@
'Add patchset description');
});
- test('_handleDescriptionChanged', () => {
+ test('description editing', () => {
const putDescStub = sandbox.stub(element.$.restAPI, 'setDescription')
.returns(Promise.resolve({ok: true}));
- sandbox.stub(element, '_computeDescriptionReadOnly');
element.changeNum = '42';
element.basePatchNum = 'PARENT';
@@ -120,14 +119,44 @@
element.loggedIn = true;
flushAsynchronousOperations();
- const label = element.$.descriptionLabel;
- assert.equal(label.value, 'test');
- label.editing = true;
- label._inputText = 'test2';
- label._save();
- flushAsynchronousOperations();
- assert.isTrue(putDescStub.called);
- assert.equal(putDescStub.args[0][2], 'test2');
+
+ // The element has a description, so the account chip should be visible
+ // and the description label should not exist.
+ const chip = Polymer.dom(element.root).querySelector('#descriptionChip');
+ let label = Polymer.dom(element.root).querySelector('#descriptionLabel');
+
+ assert.equal(chip.text, 'test');
+ assert.isNotOk(label);
+
+ // Simulate tapping the remove button, but call function directly so that
+ // can determine what happens after the promise is resolved.
+ return element._handleDescriptionRemoved().then(() => {
+ // The API stub should be called with an empty string for the new
+ // description.
+ assert.equal(putDescStub.lastCall.args[2], '');
+
+ flushAsynchronousOperations();
+ // The editable label should now be visible and the chip hidden.
+ label = Polymer.dom(element.root).querySelector('#descriptionLabel');
+ assert.isOk(label);
+ assert.equal(getComputedStyle(chip).display, 'none');
+ assert.notEqual(getComputedStyle(label).display, 'none');
+ assert.isFalse(label.readOnly);
+ // Edit the label to have a new value of test2, and save.
+ label.editing = true;
+ label._inputText = 'test2';
+ label._save();
+ flushAsynchronousOperations();
+ // The API stub should be called with an `test2` for the new
+ // description.
+ assert.equal(putDescStub.callCount, 2);
+ assert.equal(putDescStub.lastCall.args[2], 'test2');
+ }).then(() => {
+ flushAsynchronousOperations();
+ // The chip should be visible again, and the label hidden.
+ assert.equal(getComputedStyle(label).display, 'none');
+ assert.notEqual(getComputedStyle(chip).display, 'none');
+ });
});
test('expandAllDiffs called when expand button clicked', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html
index d30bad2..6159d22 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.html
@@ -68,6 +68,9 @@
opacity: .6;
pointer-events: none;
}
+ a {
+ color: var(--linked-chip-text-color);
+ }
</style>
<div class$="container [[_getBackgroundClass(transparentBackground)]]">
<a href$="[[href]]">