Show toast messages for storing diff comment drafts

With this change, toast messages show when diff comments are being saved
and notify when saving is complete, even when the diff view is no-longer
loaded. This signal is intended to encourage users to write diff
comments and feel free to navigate away to view other parts of a change.

With this change, new toast messages are able to replace existing toast
messages.

Feature: Issue 6970
Change-Id: I5973673d85c73b14794cb5e5b21327dd0c27ec1d
This commit is contained in:
Wyatt Allen
2017-09-12 17:01:42 -07:00
parent 1bd466a24b
commit 494e7d42b7
4 changed files with 89 additions and 17 deletions

View File

@@ -126,7 +126,9 @@
*/
_showAlert(text, opt_actionText, opt_actionCallback,
opt_dismissOnNavigation) {
if (this._alertElement) { return; }
if (this._alertElement) {
this._hideAlert();
}
this._clearHideAlertHandle();
if (opt_dismissOnNavigation) {

View File

@@ -272,20 +272,11 @@ limitations under the License.
});
});
test('dismissOnNavigation respected', () => {
const asyncStub = sandbox.stub(element, 'async');
const hideSpy = sandbox.spy(element, '_hideAlert');
// No async call when dismissOnNavigation supplied.
element._showAlert('test', null, null, true);
assert.isFalse(asyncStub.called);
// When page nav happens, clear alert.
document.dispatchEvent(new CustomEvent('location-change'));
assert.isTrue(hideSpy.called);
// When timeout is not supplied, use HIDE_ALERT_TIMEOUT_MS.
element._showAlert('test');
assert.isTrue(asyncStub.called);
test('_showAlert hides existing alerts', () => {
element._alertElement = element._createToastAlert();
const hideStub = sandbox.stub(element, '_hideAlert');
element._showAlert();
assert.isTrue(hideStub.calledOnce);
});
});
</script>

View File

@@ -15,6 +15,12 @@
'use strict';
const STORAGE_DEBOUNCE_INTERVAL = 400;
const TOAST_DEBOUNCE_INTERVAL = 200;
const SAVING_MESSAGE = 'Saving';
const DRAFT_SINGULAR = 'draft...';
const DRAFT_PLURAL = 'drafts...';
const SAVED_MESSAGE = 'All changes saved';
Polymer({
is: 'gr-diff-comment',
@@ -109,6 +115,11 @@
type: Boolean,
observer: '_toggleResolved',
},
_numPendingDiffRequests: {
type: Object,
value: {number: 0}, // Intentional to share the object across instances.
},
},
observers: [
@@ -424,13 +435,52 @@
});
},
_getSavingMessage(numPending) {
if (numPending === 0) { return SAVED_MESSAGE; }
return [
SAVING_MESSAGE,
numPending,
numPending === 1 ? DRAFT_SINGULAR : DRAFT_PLURAL,
].join(' ');
},
_showStartRequest() {
const numPending = ++this._numPendingDiffRequests.number;
this._updateRequestToast(numPending);
},
_showEndRequest() {
const numPending = --this._numPendingDiffRequests.number;
this._updateRequestToast(numPending);
},
_updateRequestToast(numPending) {
const message = this._getSavingMessage(numPending);
this.debounce('draft-toast', () => {
// Note: the event is fired on the body rather than this element because
// this element may not be attached by the time this executes, in which
// case the event would not bubble.
document.body.dispatchEvent(new CustomEvent('show-alert',
{detail: {message}, bubbles: true}));
}, TOAST_DEBOUNCE_INTERVAL);
},
_saveDraft(draft) {
return this.$.restAPI.saveDiffDraft(this.changeNum, this.patchNum, draft);
this._showStartRequest();
return this.$.restAPI.saveDiffDraft(this.changeNum, this.patchNum, draft)
.then(result => {
this._showEndRequest();
return result;
});
},
_deleteDraft(draft) {
this._showStartRequest();
return this.$.restAPI.deleteDiffDraft(this.changeNum, this.patchNum,
draft);
draft).then(result => {
this._showEndRequest();
return result;
});
},
_getPatchNum() {

View File

@@ -602,5 +602,34 @@ limitations under the License.
element.comment = {unresolved: true};
assert.isFalse(element.$$('.resolve input').checked);
});
suite('draft saving messages', () => {
test('_getSavingMessage', () => {
assert.equal(element._getSavingMessage(0), 'All changes saved');
assert.equal(element._getSavingMessage(1), 'Saving 1 draft...');
assert.equal(element._getSavingMessage(2), 'Saving 2 drafts...');
assert.equal(element._getSavingMessage(3), 'Saving 3 drafts...');
});
test('_show{Start,End}Request', () => {
const updateStub = sandbox.stub(element, '_updateRequestToast');
element._numPendingDiffRequests.number = 1;
element._showStartRequest();
assert.isTrue(updateStub.calledOnce);
assert.equal(updateStub.lastCall.args[0], 2);
assert.equal(element._numPendingDiffRequests.number, 2);
element._showEndRequest();
assert.isTrue(updateStub.calledTwice);
assert.equal(updateStub.lastCall.args[0], 1);
assert.equal(element._numPendingDiffRequests.number, 1);
element._showEndRequest();
assert.isTrue(updateStub.calledThrice);
assert.equal(updateStub.lastCall.args[0], 0);
assert.equal(element._numPendingDiffRequests.number, 0);
});
});
});
</script>