Merge "Add username to registration dialog"

This commit is contained in:
Becky Siegel
2017-11-18 00:30:38 +00:00
committed by Gerrit Code Review
5 changed files with 100 additions and 37 deletions

View File

@@ -372,6 +372,10 @@ limitations under the License.
detail: Gerrit.Nav.GroupDetailView.MEMBERS, detail: Gerrit.Nav.GroupDetailView.MEMBERS,
}); });
}, },
getUrlForSettings() {
return this._getUrlFor({view: Gerrit.Nav.View.SETTINGS});
},
}; };
})(window); })(window);
</script> </script>

View File

@@ -228,6 +228,8 @@
url = this._generateDiffOrEditUrl(params); url = this._generateDiffOrEditUrl(params);
} else if (params.view === Views.GROUP) { } else if (params.view === Views.GROUP) {
url = this._generateGroupUrl(params); url = this._generateGroupUrl(params);
} else if (params.view === Views.SETTINGS) {
url = this._generateSettingsUrl(params);
} else { } else {
throw new Error('Can\'t generate'); throw new Error('Can\'t generate');
} }
@@ -351,6 +353,14 @@
return url; return url;
}, },
/**
* @param {!Object} params
* @return {string}
*/
_generateSettingsUrl(params) {
return '/settings';
},
/** /**
* Given an object of parameters, potentially including a `patchNum` or a * Given an object of parameters, potentially including a `patchNum` or a
* `basePatchNum` or both, return a string representation of that range. If * `basePatchNum` or both, return a string representation of that range. If

View File

@@ -16,6 +16,7 @@ limitations under the License.
<link rel="import" href="../../../bower_components/polymer/polymer.html"> <link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../styles/gr-form-styles.html"> <link rel="import" href="../../../styles/gr-form-styles.html">
<link rel="import" href="../../core/gr-navigation/gr-navigation.html">
<link rel="import" href="../../shared/gr-button/gr-button.html"> <link rel="import" href="../../shared/gr-button/gr-button.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html"> <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../../../styles/shared-styles.html"> <link rel="import" href="../../../styles/shared-styles.html">
@@ -37,18 +38,23 @@ limitations under the License.
header { header {
border-bottom: 1px solid #cdcdcd; border-bottom: 1px solid #cdcdcd;
font-family: var(--font-family-bold); font-family: var(--font-family-bold);
margin-bottom: 1em;
} }
header, .container {
main,
footer {
padding: .5em 1.5em; padding: .5em 1.5em;
} }
footer { footer {
display: flex; display: flex;
justify-content: space-between; justify-content: flex-end;
}
footer gr-button {
margin-left: 1em;
}
input {
width: 20em;
} }
</style> </style>
<main class="gr-form-styles"> <div class="container gr-form-styles">
<header>Please confirm your contact information</header> <header>Please confirm your contact information</header>
<main> <main>
<p> <p>
@@ -64,8 +70,15 @@ limitations under the License.
is="iron-input" is="iron-input"
id="name" id="name"
bind-value="{{_account.name}}" bind-value="{{_account.name}}"
disabled="[[_saving]]" disabled="[[_saving]]">
on-keydown="_handleNameKeydown"> </section>
<section>
<div class="title">Username</div>
<input
is="iron-input"
id="username"
bind-value="{{_account.username}}"
disabled="[[_saving]]">
</section> </section>
<section> <section>
<div class="title">Preferred Email</div> <div class="title">Preferred Email</div>
@@ -78,19 +91,26 @@ limitations under the License.
</template> </template>
</select> </select>
</section> </section>
<hr>
<p>
More configuration options for Gerrit may be found in the
<a on-tap="close" href$="[[_computeSettingsUrl(_account)]]">settings</a>.
</p>
</main> </main>
<footer> <footer>
<gr-button
id="saveButton"
primary
disabled="[[_saving]]"
on-tap="_handleSave">Save</gr-button>
<gr-button <gr-button
id="closeButton" id="closeButton"
link
disabled="[[_saving]]" disabled="[[_saving]]"
on-tap="_handleClose">Close</gr-button> on-tap="_handleClose">Close</gr-button>
<gr-button
id="saveButton"
primary
link
disabled="[[_computeSaveDisabled(_account.name, _account.username, _account.email, _saving)]]"
on-tap="_handleSave">Save</gr-button>
</footer> </footer>
</main> </div>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface> <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template> </template>
<script src="gr-registration-dialog.js"></script> <script src="gr-registration-dialog.js"></script>

View File

@@ -31,8 +31,18 @@
properties: { properties: {
/** @type {?} */ /** @type {?} */
_account: Object, _account: {
_saving: Boolean, type: Object,
value: () => {
// Prepopulate possibly undefined fields with values to trigger
// computed bindings.
return {email: null, name: null, username: null};
},
},
_saving: {
type: Boolean,
value: false,
},
}, },
hostAttributes: { hostAttributes: {
@@ -41,22 +51,19 @@
attached() { attached() {
this.$.restAPI.getAccount().then(account => { this.$.restAPI.getAccount().then(account => {
this._account = account; // Using Object.assign here allows preservation of the default values
// supplied in the value generating function of this._account, unless
// they are overridden by properties in the account from the response.
this._account = Object.assign({}, this._account, account);
}); });
}, },
_handleNameKeydown(e) {
if (e.keyCode === 13) { // Enter
e.stopPropagation();
this._save();
}
},
_save() { _save() {
this._saving = true; this._saving = true;
const promises = [ const promises = [
this.$.restAPI.setAccountName(this.$.name.value), this.$.restAPI.setAccountName(this.$.name.value),
this.$.restAPI.setPreferredAccountEmail(this.$.email.value), this.$.restAPI.setAccountUsername(this.$.username.value),
this.$.restAPI.setPreferredAccountEmail(this.$.email.value || ''),
]; ];
return Promise.all(promises).then(() => { return Promise.all(promises).then(() => {
this._saving = false; this._saving = false;
@@ -66,15 +73,25 @@
_handleSave(e) { _handleSave(e) {
e.preventDefault(); e.preventDefault();
this._save().then(() => { this._save().then(this.close.bind(this));
this.fire('close');
});
}, },
_handleClose(e) { _handleClose(e) {
e.preventDefault(); e.preventDefault();
this.close();
},
close() {
this._saving = true; // disable buttons indefinitely this._saving = true; // disable buttons indefinitely
this.fire('close'); this.fire('close');
}, },
_computeSaveDisabled(name, username, email, saving) {
return !name || !username || !email || saving;
},
_computeSettingsUrl() {
return Gerrit.Nav.getUrlForSettings();
},
}); });
})(); })();

View File

@@ -41,13 +41,16 @@ limitations under the License.
suite('gr-registration-dialog tests', () => { suite('gr-registration-dialog tests', () => {
let element; let element;
let account; let account;
let sandbox;
let _listeners; let _listeners;
setup(done => { setup(done => {
sandbox = sinon.sandbox.create();
_listeners = {}; _listeners = {};
account = { account = {
name: 'name', name: 'name',
username: 'username',
email: 'email', email: 'email',
secondary_emails: [ secondary_emails: [
'email2', 'email2',
@@ -65,6 +68,10 @@ limitations under the License.
account.name = name; account.name = name;
return Promise.resolve(); return Promise.resolve();
}, },
setAccountUsername(username) {
account.username = username;
return Promise.resolve();
},
setPreferredAccountEmail(email) { setPreferredAccountEmail(email) {
account.email = email; account.email = email;
return Promise.resolve(); return Promise.resolve();
@@ -75,6 +82,7 @@ limitations under the License.
}); });
teardown(() => { teardown(() => {
sandbox.restore();
for (const eventType in _listeners) { for (const eventType in _listeners) {
if (_listeners.hasOwnProperty(eventType)) { if (_listeners.hasOwnProperty(eventType)) {
element.removeEventListener(eventType, _listeners[eventType]); element.removeEventListener(eventType, _listeners[eventType]);
@@ -119,32 +127,26 @@ limitations under the License.
}).then(done); }).then(done);
}); });
test('saves name and preferred email', done => { test('saves account details', done => {
flush(() => { flush(() => {
element.$.name.value = 'new name'; element.$.name.value = 'new name';
element.$.username.value = 'new username';
element.$.email.value = 'email3'; element.$.email.value = 'email3';
// Nothing should be committed yet. // Nothing should be committed yet.
assert.equal(account.name, 'name'); assert.equal(account.name, 'name');
assert.equal(account.username, 'username');
assert.equal(account.email, 'email'); assert.equal(account.email, 'email');
// Save and verify new values are committed. // Save and verify new values are committed.
save().then(() => { save().then(() => {
assert.equal(account.name, 'new name'); assert.equal(account.name, 'new name');
assert.equal(account.username, 'new username');
assert.equal(account.email, 'email3'); assert.equal(account.email, 'email3');
}).then(done); }).then(done);
}); });
}); });
test('pressing enter saves name', done => {
element.$.name.value = 'entered name';
save(() => {
MockInteractions.pressAndReleaseKeyOn(element.$.name, 13); // 'enter'
}).then(() => {
assert.equal(account.name, 'entered name');
}).then(done);
});
test('email select properly populated', done => { test('email select properly populated', done => {
element._account = {email: 'foo', secondary_emails: ['bar', 'baz']}; element._account = {email: 'foo', secondary_emails: ['bar', 'baz']};
flush(() => { flush(() => {
@@ -152,5 +154,15 @@ limitations under the License.
done(); done();
}); });
}); });
test('save btn disabled', () => {
const compute = element._computeSaveDisabled;
assert.isTrue(compute('', '', '', false));
assert.isTrue(compute('', 'test', 'test', false));
assert.isTrue(compute('test', '', 'test', false));
assert.isTrue(compute('test', 'test', '', false));
assert.isTrue(compute('test', 'test', 'test', true));
assert.isFalse(compute('test', 'test', 'test', false));
});
}); });
</script> </script>